PageSourceSearch

https://apa1906.net/wp-content/themes/uncode/library/js/plugins.js?ver=1136178739

js apa1906.net collected 2026-09-24 09:37:26 UTC 1,868,701 bytes, 56,595 lines download raw bytes

vendor: 4,970 bytes, lines 1-161
1/* ----------------------------------------------------------
2 * Plugins
3 * ---------------------------------------------------------- */
4
5(function (global, factory) {
6  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
7  typeof define === 'function' && define.amd ? define(['exports'], factory) :
8  (global = global || self, factory(global.window = global.window || {}));
9}(this, (function (exports) { 'use strict';
10
11  function _inheritsLoose(subClass, superClass) {
12    subClass.prototype = Object.create(superClass.prototype);
13    subClass.prototype.constructor = subClass;
14    subClass.__proto__ = superClass;
15  }
16
17  function _assertThisInitialized(self) {
18    if (self === void 0) {
19      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
20    }
21
22    return self;
23  }
24
25  /*!
26   * GSAP 3.12.5
27   * https://gsap.com
28   *
29   * @license Copyright 2008-2024, GreenSock. All rights reserved.
30   * Subject to the terms at https://gsap.com/standard-license or for
31   * Club GSAP members, the agreement issued with that membership.
32   * @author: Jack Doyle, [email protected]
33  */
34  var _config = {
35    autoSleep: 120,
36    force3D: "auto",
37    nullTargetWarn: 1,
38    units: {
39      lineHeight: ""
40    }
41  },
42      _defaults = {
43    duration: .5,
44    overwrite: false,
45    delay: 0
46  },
47      _suppressOverwrites,
48      _reverting,
49      _context,
50      _bigNum = 1e8,
51      _tinyNum = 1 / _bigNum,
52      _2PI = Math.PI * 2,
53      _HALF_PI = _2PI / 4,
54      _gsID = 0,
55      _sqrt = Math.sqrt,
56      _cos = Math.cos,
57      _sin = Math.sin,
58      _isString = function _isString(value) {
59    return typeof value === "string";
60  },
61      _isFunction = function _isFunction(value) {
62    return typeof value === "function";
63  },
64      _isNumber = function _isNumber(value) {
65    return typeof value === "number";
66  },
67      _isUndefined = function _isUndefined(value) {
68    return typeof value === "undefined";
69  },
70      _isObject = function _isObject(value) {
71    return typeof value === "object";
72  },
73      _isNotFalse = function _isNotFalse(value) {
74    return value !== false;
75  },
76      _windowExists = function _windowExists() {
77    return typeof window !== "undefined";
78  },
79      _isFuncOrString = function _isFuncOrString(value) {
80    return _isFunction(value) || _isString(value);
81  },
82      _isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView || function () {},
83      _isArray = Array.isArray,
84      _strictNumExp = /(?:-?\.?\d|\.)+/gi,
85      _numExp = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/g,
86      _numWithUnitExp = /[-+=.]*\d+[.e-]*\d*[a-z%]*/g,
87      _complexStringNumExp = /[-+=.]*\d+\.?\d*(?:e-|e\+)?\d*/gi,
88      _relExp = /[+-]=-?[.\d]+/,
89      _delimitedValueExp = /[^,'"\[\]\s]+/gi,
90      _unitExp = /^[+\-=e\s\d]*\d+[.\d]*([a-z]*|%)\s*$/i,
91      _globalTimeline,
92      _win,
93      _coreInitted,
94      _doc,
95      _globals = {},
96      _installScope = {},
97      _coreReady,
98      _install = function _install(scope) {
99    return (_installScope = _merge(scope, _globals)) && gsap;
100  },
101      _missingPlugin = function _missingPlugin(property, value) {
102    return console.warn("Invalid property", property, "set to", value, "Missing plugin? gsap.registerPlugin()");
103  },
104      _warn = function _warn(message, suppress) {
105    return !suppress && console.warn(message);
106  },
107      _addGlobal = function _addGlobal(name, obj) {
108    return name && (_globals[name] = obj) && _installScope && (_installScope[name] = obj) || _globals;
109  },
110      _emptyFunc = function _emptyFunc() {
111    return 0;
112  },
113      _startAtRevertConfig = {
114    suppressEvents: true,
115    isStart: true,
116    kill: false
117  },
118      _revertConfigNoKill = {
119    suppressEvents: true,
120    kill: false
121  },
122      _revertConfig = {
123    suppressEvents: true
124  },
125      _reservedProps = {},
126      _lazyTweens = [],
127      _lazyLookup = {},
128      _lastRenderedFrame,
129      _plugins = {},
130      _effects = {},
131      _nextGCFrame = 30,
132      _harnessPlugins = [],
133      _callbackNames = "",
134      _harness = function _harness(targets) {
135    var target = targets[0],
136        harnessPlugin,
137        i;
138    _isObject(target) || _isFunction(target) || (targets = [targets]);
139
140    if (!(harnessPlugin = (target._gsap || {}).harness)) {
141      i = _harnessPlugins.length;
142
143      while (i-- && !_harnessPlugins[i].targetTest(target)) {}
144
145      harnessPlugin = _harnessPlugins[i];
146    }
147
148    i = targets.length;
149
150    while (i--) {
151      targets[i] && (targets[i]._gsap || (targets[i]._gsap = new GSCache(targets[i], harnessPlugin))) || targets.splice(i, 1);
152    }
153
154    return targets;
155  },
156      _getCache = function _getCache(target) {
157    return target._gsap || _harness(toArray(target))[0]._gsap;
158  },
159      _getProperty = function _getProperty(target, property, v) {
160    return (v = target[property]) && _isFunction(v) ? target[property]() : _isUndefined(v) && target.getAttribute && target.getAttribute(property) || v;
161  },
vendor: 6,338 bytes, lines 162-371
162      _forEachName = function _forEachName(names, func) {
163    return (names = names.split(",")).forEach(func) || names;
164  },
165      _round = function _round(value) {
166    return Math.round(value * 100000) / 100000 || 0;
167  },
168      _roundPrecise = function _roundPrecise(value) {
169    return Math.round(value * 10000000) / 10000000 || 0;
170  },
171      _parseRelative = function _parseRelative(start, value) {
172    var operator = value.charAt(0),
173        end = parseFloat(value.substr(2));
174    start = parseFloat(start);
175    return operator === "+" ? start + end : operator === "-" ? start - end : operator === "*" ? start * end : start / end;
176  },
177      _arrayContainsAny = function _arrayContainsAny(toSearch, toFind) {
178    var l = toFind.length,
179        i = 0;
180
181    for (; toSearch.indexOf(toFind[i]) < 0 && ++i < l;) {}
182
183    return i < l;
184  },
185      _lazyRender = function _lazyRender() {
186    var l = _lazyTweens.length,
187        a = _lazyTweens.slice(0),
188        i,
189        tween;
190
191    _lazyLookup = {};
192    _lazyTweens.length = 0;
193
194    for (i = 0; i < l; i++) {
195      tween = a[i];
196      tween && tween._lazy && (tween.render(tween._lazy[0], tween._lazy[1], true)._lazy = 0);
197    }
198  },
199      _lazySafeRender = function _lazySafeRender(animation, time, suppressEvents, force) {
200    _lazyTweens.length && !_reverting && _lazyRender();
201    animation.render(time, suppressEvents, force || _reverting && time < 0 && (animation._initted || animation._startAt));
202    _lazyTweens.length && !_reverting && _lazyRender();
203  },
204      _numericIfPossible = function _numericIfPossible(value) {
205    var n = parseFloat(value);
206    return (n || n === 0) && (value + "").match(_delimitedValueExp).length < 2 ? n : _isString(value) ? value.trim() : value;
207  },
208      _passThrough = function _passThrough(p) {
209    return p;
210  },
211      _setDefaults = function _setDefaults(obj, defaults) {
212    for (var p in defaults) {
213      p in obj || (obj[p] = defaults[p]);
214    }
215
216    return obj;
217  },
218      _setKeyframeDefaults = function _setKeyframeDefaults(excludeDuration) {
219    return function (obj, defaults) {
220      for (var p in defaults) {
221        p in obj || p === "duration" && excludeDuration || p === "ease" || (obj[p] = defaults[p]);
222      }
223    };
224  },
225      _merge = function _merge(base, toMerge) {
226    for (var p in toMerge) {
227      base[p] = toMerge[p];
228    }
229
230    return base;
231  },
232      _mergeDeep = function _mergeDeep(base, toMerge) {
233    for (var p in toMerge) {
234      p !== "__proto__" && p !== "constructor" && p !== "prototype" && (base[p] = _isObject(toMerge[p]) ? _mergeDeep(base[p] || (base[p] = {}), toMerge[p]) : toMerge[p]);
235    }
236
237    return base;
238  },
239      _copyExcluding = function _copyExcluding(obj, excluding) {
240    var copy = {},
241        p;
242
243    for (p in obj) {
244      p in excluding || (copy[p] = obj[p]);
245    }
246
247    return copy;
248  },
249      _inheritDefaults = function _inheritDefaults(vars) {
250    var parent = vars.parent || _globalTimeline,
251        func = vars.keyframes ? _setKeyframeDefaults(_isArray(vars.keyframes)) : _setDefaults;
252
253    if (_isNotFalse(vars.inherit)) {
254      while (parent) {
255        func(vars, parent.vars.defaults);
256        parent = parent.parent || parent._dp;
257      }
258    }
259
260    return vars;
261  },
262      _arraysMatch = function _arraysMatch(a1, a2) {
263    var i = a1.length,
264        match = i === a2.length;
265
266    while (match && i-- && a1[i] === a2[i]) {}
267
268    return i < 0;
269  },
270      _addLinkedListItem = function _addLinkedListItem(parent, child, firstProp, lastProp, sortBy) {
271    if (firstProp === void 0) {
272      firstProp = "_first";
273    }
274
275    if (lastProp === void 0) {
276      lastProp = "_last";
277    }
278
279    var prev = parent[lastProp],
280        t;
281
282    if (sortBy) {
283      t = child[sortBy];
284
285      while (prev && prev[sortBy] > t) {
286        prev = prev._prev;
287      }
288    }
289
290    if (prev) {
291      child._next = prev._next;
292      prev._next = child;
293    } else {
294      child._next = parent[firstProp];
295      parent[firstProp] = child;
296    }
297
298    if (child._next) {
299      child._next._prev = child;
300    } else {
301      parent[lastProp] = child;
302    }
303
304    child._prev = prev;
305    child.parent = child._dp = parent;
306    return child;
307  },
308      _removeLinkedListItem = function _removeLinkedListItem(parent, child, firstProp, lastProp) {
309    if (firstProp === void 0) {
310      firstProp = "_first";
311    }
312
313    if (lastProp === void 0) {
314      lastProp = "_last";
315    }
316
317    var prev = child._prev,
318        next = child._next;
319
320    if (prev) {
321      prev._next = next;
322    } else if (parent[firstProp] === child) {
323      parent[firstProp] = next;
324    }
325
326    if (next) {
327      next._prev = prev;
328    } else if (parent[lastProp] === child) {
329      parent[lastProp] = prev;
330    }
331
332    child._next = child._prev = child.parent = null;
333  },
334      _removeFromParent = function _removeFromParent(child, onlyIfParentHasAutoRemove) {
335    child.parent && (!onlyIfParentHasAutoRemove || child.parent.autoRemoveChildren) && child.parent.remove && child.parent.remove(child);
336    child._act = 0;
337  },
338      _uncache = function _uncache(animation, child) {
339    if (animation && (!child || child._end > animation._dur || child._start < 0)) {
340      var a = animation;
341
342      while (a) {
343        a._dirty = 1;
344        a = a.parent;
345      }
346    }
347
348    return animation;
349  },
350      _recacheAncestors = function _recacheAncestors(animation) {
351    var parent = animation.parent;
352
353    while (parent && parent.parent) {
354      parent._dirty = 1;
355      parent.totalDuration();
356      parent = parent.parent;
357    }
358
359    return animation;
360  },
361      _rewindStartAt = function _rewindStartAt(tween, totalTime, suppressEvents, force) {
362    return tween._startAt && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween.vars.immediateRender && !tween.vars.autoRevert || tween._startAt.render(totalTime, true, force));
363  },
364      _hasNoPausedAncestors = function _hasNoPausedAncestors(animation) {
365    return !animation || animation._ts && _hasNoPausedAncestors(animation.parent);
366  },
367      _elapsedCycleDuration = function _elapsedCycleDuration(animation) {
368    return animation._repeat ? _animationCycle(animation._tTime, animation = animation.duration() + animation._rDelay) * animation : 0;
369  },
370      _animationCycle = function _animationCycle(tTime, cycleDuration) {
371    var whole = Math.floor(tTime /= cycleDuration
vendor: 17,487 bytes, lines 371-839
371);
372    return tTime && whole === tTime ? whole - 1 : whole;
373  },
374      _parentToChildTotalTime = function _parentToChildTotalTime(parentTime, child) {
375    return (parentTime - child._start) * child._ts + (child._ts >= 0 ? 0 : child._dirty ? child.totalDuration() : child._tDur);
376  },
377      _setEnd = function _setEnd(animation) {
378    return animation._end = _roundPrecise(animation._start + (animation._tDur / Math.abs(animation._ts || animation._rts || _tinyNum) || 0));
379  },
380      _alignPlayhead = function _alignPlayhead(animation, totalTime) {
381    var parent = animation._dp;
382
383    if (parent && parent.smoothChildTiming && animation._ts) {
384      animation._start = _roundPrecise(parent._time - (animation._ts > 0 ? totalTime / animation._ts : ((animation._dirty ? animation.totalDuration() : animation._tDur) - totalTime) / -animation._ts));
385
386      _setEnd(animation);
387
388      parent._dirty || _uncache(parent, animation);
389    }
390
391    return animation;
392  },
393      _postAddChecks = function _postAddChecks(timeline, child) {
394    var t;
395
396    if (child._time || !child._dur && child._initted || child._start < timeline._time && (child._dur || !child.add)) {
397      t = _parentToChildTotalTime(timeline.rawTime(), child);
398
399      if (!child._dur || _clamp(0, child.totalDuration(), t) - child._tTime > _tinyNum) {
400        child.render(t, true);
401      }
402    }
403
404    if (_uncache(timeline, child)._dp && timeline._initted && timeline._time >= timeline._dur && timeline._ts) {
405      if (timeline._dur < timeline.duration()) {
406        t = timeline;
407
408        while (t._dp) {
409          t.rawTime() >= 0 && t.totalTime(t._tTime);
410          t = t._dp;
411        }
412      }
413
414      timeline._zTime = -_tinyNum;
415    }
416  },
417      _addToTimeline = function _addToTimeline(timeline, child, position, skipChecks) {
418    child.parent && _removeFromParent(child);
419    child._start = _roundPrecise((_isNumber(position) ? position : position || timeline !== _globalTimeline ? _parsePosition(timeline, position, child) : timeline._time) + child._delay);
420    child._end = _roundPrecise(child._start + (child.totalDuration() / Math.abs(child.timeScale()) || 0));
421
422    _addLinkedListItem(timeline, child, "_first", "_last", timeline._sort ? "_start" : 0);
423
424    _isFromOrFromStart(child) || (timeline._recent = child);
425    skipChecks || _postAddChecks(timeline, child);
426    timeline._ts < 0 && _alignPlayhead(timeline, timeline._tTime);
427    return timeline;
428  },
429      _scrollTrigger = function _scrollTrigger(animation, trigger) {
430    return (_globals.ScrollTrigger || _missingPlugin("scrollTrigger", trigger)) && _globals.ScrollTrigger.create(trigger, animation);
431  },
432      _attemptInitTween = function _attemptInitTween(tween, time, force, suppressEvents, tTime) {
433    _initTween(tween, time, tTime);
434
435    if (!tween._initted) {
436      return 1;
437    }
438
439    if (!force && tween._pt && !_reverting && (tween._dur && tween.vars.lazy !== false || !tween._dur && tween.vars.lazy) && _lastRenderedFrame !== _ticker.frame) {
440      _lazyTweens.push(tween);
441
442      tween._lazy = [tTime, suppressEvents];
443      return 1;
444    }
445  },
446      _parentPlayheadIsBeforeStart = function _parentPlayheadIsBeforeStart(_ref) {
447    var parent = _ref.parent;
448    return parent && parent._ts && parent._initted && !parent._lock && (parent.rawTime() < 0 || _parentPlayheadIsBeforeStart(parent));
449  },
450      _isFromOrFromStart = function _isFromOrFromStart(_ref2) {
451    var data = _ref2.data;
452    return data === "isFromStart" || data === "isStart";
453  },
454      _renderZeroDurationTween = function _renderZeroDurationTween(tween, totalTime, suppressEvents, force) {
455    var prevRatio = tween.ratio,
456        ratio = totalTime < 0 || !totalTime && (!tween._start && _parentPlayheadIsBeforeStart(tween) && !(!tween._initted && _isFromOrFromStart(tween)) || (tween._ts < 0 || tween._dp._ts < 0) && !_isFromOrFromStart(tween)) ? 0 : 1,
457        repeatDelay = tween._rDelay,
458        tTime = 0,
459        pt,
460        iteration,
461        prevIteration;
462
463    if (repeatDelay && tween._repeat) {
464      tTime = _clamp(0, tween._tDur, totalTime);
465      iteration = _animationCycle(tTime, repeatDelay);
466      tween._yoyo && iteration & 1 && (ratio = 1 - ratio);
467
468      if (iteration !== _animationCycle(tween._tTime, repeatDelay)) {
469        prevRatio = 1 - ratio;
470        tween.vars.repeatRefresh && tween._initted && tween.invalidate();
471      }
472    }
473
474    if (ratio !== prevRatio || _reverting || force || tween._zTime === _tinyNum || !totalTime && tween._zTime) {
475      if (!tween._initted && _attemptInitTween(tween, totalTime, force, suppressEvents, tTime)) {
476        return;
477      }
478
479      prevIteration = tween._zTime;
480      tween._zTime = totalTime || (suppressEvents ? _tinyNum : 0);
481      suppressEvents || (suppressEvents = totalTime && !prevIteration);
482      tween.ratio = ratio;
483      tween._from && (ratio = 1 - ratio);
484      tween._time = 0;
485      tween._tTime = tTime;
486      pt = tween._pt;
487
488      while (pt) {
489        pt.r(ratio, pt.d);
490        pt = pt._next;
491      }
492
493      totalTime < 0 && _rewindStartAt(tween, totalTime, suppressEvents, true);
494      tween._onUpdate && !suppressEvents && _callback(tween, "onUpdate");
495      tTime && tween._repeat && !suppressEvents && tween.parent && _callback(tween, "onRepeat");
496
497      if ((totalTime >= tween._tDur || totalTime < 0) && tween.ratio === ratio) {
498        ratio && _removeFromParent(tween, 1);
499
500        if (!suppressEvents && !_reverting) {
501          _callback(tween, ratio ? "onComplete" : "onReverseComplete", true);
502
503          tween._prom && tween._prom();
504        }
505      }
506    } else if (!tween._zTime) {
507      tween._zTime = totalTime;
508    }
509  },
510      _findNextPauseTween = function _findNextPauseTween(animation, prevTime, time) {
511    var child;
512
513    if (time > prevTime) {
514      child = animation._first;
515
516      while (child && child._start <= time) {
517        if (child.data === "isPause" && child._start > prevTime) {
518          return child;
519        }
520
521        child = child._next;
522      }
523    } else {
524      child = animation._last;
525
526      while (child && child._start >= time) {
527        if (child.data === "isPause" && child._start < prevTime) {
528          return child;
529        }
530
531        child = child._prev;
532      }
533    }
534  },
535      _setDuration = function _setDuration(animation, duration, skipUncache, leavePlayhead) {
536    var repeat = animation._repeat,
537        dur = _roundPrecise(duration) || 0,
538        totalProgress = animation._tTime / animation._tDur;
539    totalProgress && !leavePlayhead && (animation._time *= dur / animation._dur);
540    animation._dur = dur;
541    animation._tDur = !repeat ? dur : repeat < 0 ? 1e10 : _roundPrecise(dur * (repeat + 1) + animation._rDelay * repeat);
542    totalProgress > 0 && !leavePlayhead && _alignPlayhead(animation, animation._tTime = animation._tDur * totalProgress);
543    animation.parent && _setEnd(animation);
544    skipUncache || _uncache(animation.parent, animation);
545    return animation;
546  },
547      _onUpdateTotalDuration = function _onUpdateTotalDuration(animation) {
548    return animation instanceof Timeline ? _uncache(animation) : _setDuration(animation, animation._dur);
549  },
550      _zeroPosition = {
551    _start: 0,
552    endTime: _emptyFunc,
553    totalDuration: _emptyFunc
554  },
555      _parsePosition = function _parsePosition(animation, position, percentAnimation) {
556    var labels = animation.labels,
557        recent = animation._recent || _zeroPosition,
558        clippedDuration = animation.duration() >= _bigNum ? recent.endTime(false) : animation._dur,
559        i,
560        offset,
561        isPercent;
562
563    if (_isString(position) && (isNaN(position) || position in labels)) {
564      offset = position.charAt(0);
565      isPercent = position.substr(-1) === "%";
566      i = position.indexOf("=");
567
568      if (offset === "<" || offset === ">") {
569        i >= 0 && (position = position.replace(/=/, ""));
570        return (offset === "<" ? recent._start : recent.endTime(recent._repeat >= 0)) + (parseFloat(position.substr(1)) || 0) * (isPercent ? (i < 0 ? recent : percentAnimation).totalDuration() / 100 : 1);
571      }
572
573      if (i < 0) {
574        position in labels || (labels[position] = clippedDuration);
575        return labels[position];
576      }
577
578      offset = parseFloat(position.charAt(i - 1) + position.substr(i + 1));
579
580      if (isPercent && percentAnimation) {
581        offset = offset / 100 * (_isArray(percentAnimation) ? percentAnimation[0] : percentAnimation).totalDuration();
582      }
583
584      return i > 1 ? _parsePosition(animation, position.substr(0, i - 1), percentAnimation) + offset : clippedDuration + offset;
585    }
586
587    return position == null ? clippedDuration : +position;
588  },
589      _createTweenType = function _createTweenType(type, params, timeline) {
590    var isLegacy = _isNumber(params[1]),
591        varsIndex = (isLegacy ? 2 : 1) + (type < 2 ? 0 : 1),
592        vars = params[varsIndex],
593        irVars,
594        parent;
595
596    isLegacy && (vars.duration = params[1]);
597    vars.parent = timeline;
598
599    if (type) {
600      irVars = vars;
601      parent = timeline;
602
603      while (parent && !("immediateRender" in irVars)) {
604        irVars = parent.vars.defaults || {};
605        parent = _isNotFalse(parent.vars.inherit) && parent.parent;
606      }
607
608      vars.immediateRender = _isNotFalse(irVars.immediateRender);
609      type < 2 ? vars.runBackwards = 1 : vars.startAt = params[varsIndex - 1];
610    }
611
612    return new Tween(params[0], vars, params[varsIndex + 1]);
613  },
614      _conditionalReturn = function _conditionalReturn(value, func) {
615    return value || value === 0 ? func(value) : func;
616  },
617      _clamp = function _clamp(min, max, value) {
618    return value < min ? min : value > max ? max : value;
619  },
620      getUnit = function getUnit(value, v) {
621    return !_isString(value) || !(v = _unitExp.exec(value)) ? "" : v[1];
622  },
623      clamp = function clamp(min, max, value) {
624    return _conditionalReturn(value, function (v) {
625      return _clamp(min, max, v);
626    });
627  },
628      _slice = [].slice,
629      _isArrayLike = function _isArrayLike(value, nonEmpty) {
630    return value && _isObject(value) && "length" in value && (!nonEmpty && !value.length || value.length - 1 in value && _isObject(value[0])) && !value.nodeType && value !== _win;
631  },
632      _flatten = function _flatten(ar, leaveStrings, accumulator) {
633    if (accumulator === void 0) {
634      accumulator = [];
635    }
636
637    return ar.forEach(function (value) {
638      var _accumulator;
639
640      return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value);
641    }) || accumulator;
642  },
643      toArray = function toArray(value, scope, leaveStrings) {
644    return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call((scope || _doc).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : [];
645  },
646      selector = function selector(value) {
647    value = toArray(value)[0] || _warn("Invalid scope") || {};
648    return function (v) {
649      var el = value.current || value.nativeElement || value;
650      return toArray(v, el.querySelectorAll ? el : el === value ? _warn("Invalid scope") || _doc.createElement("div") : value);
651    };
652  },
653      shuffle = function shuffle(a) {
654    return a.sort(function () {
655      return .5 - Math.random();
656    });
657  },
658      distribute = function distribute(v) {
659    if (_isFunction(v)) {
660      return v;
661    }
662
663    var vars = _isObject(v) ? v : {
664      each: v
665    },
666        ease = _parseEase(vars.ease),
667        from = vars.from || 0,
668        base = parseFloat(vars.base) || 0,
669        cache = {},
670        isDecimal = from > 0 && from < 1,
671        ratios = isNaN(from) || isDecimal,
672        axis = vars.axis,
673        ratioX = from,
674        ratioY = from;
675
676    if (_isString(from)) {
677      ratioX = ratioY = {
678        center: .5,
679        edges: .5,
680        end: 1
681      }[from] || 0;
682    } else if (!isDecimal && ratios) {
683      ratioX = from[0];
684      ratioY = from[1];
685    }
686
687    return function (i, target, a) {
688      var l = (a || vars).length,
689          distances = cache[l],
690          originX,
691          originY,
692          x,
693          y,
694          d,
695          j,
696          max,
697          min,
698          wrapAt;
699
700      if (!distances) {
701        wrapAt = vars.grid === "auto" ? 0 : (vars.grid || [1, _bigNum])[1];
702
703        if (!wrapAt) {
704          max = -_bigNum;
705
706          while (max < (max = a[wrapAt++].getBoundingClientRect().left) && wrapAt < l) {}
707
708          wrapAt < l && wrapAt--;
709        }
710
711        distances = cache[l] = [];
712        originX = ratios ? Math.min(wrapAt, l) * ratioX - .5 : from % wrapAt;
713        originY = wrapAt === _bigNum ? 0 : ratios ? l * ratioY / wrapAt - .5 : from / wrapAt | 0;
714        max = 0;
715        min = _bigNum;
716
717        for (j = 0; j < l; j++) {
718          x = j % wrapAt - originX;
719          y = originY - (j / wrapAt | 0);
720          distances[j] = d = !axis ? _sqrt(x * x + y * y) : Math.abs(axis === "y" ? y : x);
721          d > max && (max = d);
722          d < min && (min = d);
723        }
724
725        from === "random" && shuffle(distances);
726        distances.max = max - min;
727        distances.min = min;
728        distances.v = l = (parseFloat(vars.amount) || parseFloat(vars.each) * (wrapAt > l ? l - 1 : !axis ? Math.max(wrapAt, l / wrapAt) : axis === "y" ? l / wrapAt : wrapAt) || 0) * (from === "edges" ? -1 : 1);
729        distances.b = l < 0 ? base - l : base;
730        distances.u = getUnit(vars.amount || vars.each) || 0;
731        ease = ease && l < 0 ? _invertEase(ease) : ease;
732      }
733
734      l = (distances[i] - distances.min) / distances.max || 0;
735      return _roundPrecise(distances.b + (ease ? ease(l) : l) * distances.v) + distances.u;
736    };
737  },
738      _roundModifier = function _roundModifier(v) {
739    var p = Math.pow(10, ((v + "").split(".")[1] || "").length);
740    return function (raw) {
741      var n = _roundPrecise(Math.round(parseFloat(raw) / v) * v * p);
742
743      return (n - n % 1) / p + (_isNumber(raw) ? 0 : getUnit(raw));
744    };
745  },
746      snap = function snap(snapTo, value) {
747    var isArray = _isArray(snapTo),
748        radius,
749        is2D;
750
751    if (!isArray && _isObject(snapTo)) {
752      radius = isArray = snapTo.radius || _bigNum;
753
754      if (snapTo.values) {
755        snapTo = toArray(snapTo.values);
756
757        if (is2D = !_isNumber(snapTo[0])) {
758          radius *= radius;
759        }
760      } else {
761        snapTo = _roundModifier(snapTo.increment);
762      }
763    }
764
765    return _conditionalReturn(value, !isArray ? _roundModifier(snapTo) : _isFunction(snapTo) ? function (raw) {
766      is2D = snapTo(raw);
767      return Math.abs(is2D - raw) <= radius ? is2D : raw;
768    } : function (raw) {
769      var x = parseFloat(is2D ? raw.x : raw),
770          y = parseFloat(is2D ? raw.y : 0),
771          min = _bigNum,
772          closest = 0,
773          i = snapTo.length,
774          dx,
775          dy;
776
777      while (i--) {
778        if (is2D) {
779          dx = snapTo[i].x - x;
780          dy = snapTo[i].y - y;
781          dx = dx * dx + dy * dy;
782        } else {
783          dx = Math.abs(snapTo[i] - x);
784        }
785
786        if (dx < min) {
787          min = dx;
788          closest = i;
789        }
790      }
791
792      closest = !radius || min <= radius ? snapTo[closest] : raw;
793      return is2D || closest === raw || _isNumber(raw) ? closest : closest + getUnit(raw);
794    });
795  },
796      random = function random(min, max, roundingIncrement, returnFunction) {
797    return _conditionalReturn(_isArray(min) ? !max : roundingIncrement === true ? !!(roundingIncrement = 0) : !returnFunction, function () {
798      return _isArray(min) ? min[~~(Math.random() * min.length)] : (roundingIncrement = roundingIncrement || 1e-5) && (returnFunction = roundingIncrement < 1 ? Math.pow(10, (roundingIncrement + "").length - 2) : 1) && Math.floor(Math.round((min - roundingIncrement / 2 + Math.random() * (max - min + roundingIncrement * .99)) / roundingIncrement) * roundingIncrement * returnFunction) / returnFunction;
799    });
800  },
801      pipe = function pipe() {
802    for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) {
803      functions[_key] = arguments[_key];
804    }
805
806    return function (value) {
807      return functions.reduce(function (v, f) {
808        return f(v);
809      }, value);
810    };
811  },
812      unitize = function unitize(func, unit) {
813    return function (value) {
814      return func(parseFloat(value)) + (unit || getUnit(value));
815    };
816  },
817      normalize = function normalize(min, max, value) {
818    return mapRange(min, max, 0, 1, value);
819  },
820      _wrapArray = function _wrapArray(a, wrapper, value) {
821    return _conditionalReturn(value, function (index) {
822      return a[~~wrapper(index)];
823    });
824  },
825      wrap = function wrap(min, max, value) {
826    var range = max - min;
827    return _isArray(min) ? _wrapArray(min, wrap(0, min.length), max) : _conditionalReturn(value, function (value) {
828      return (range + (value - min) % range) % range + min;
829    });
830  },
831      wrapYoyo = function wrapYoyo(min, max, value) {
832    var range = max - min,
833        total = range * 2;
834    return _isArray(min) ? _wrapArray(min, wrapYoyo(0, min.length - 1), max) : _conditionalReturn(value, function (value) {
835      value = (total + (value - min) % total) % total || 0;
836      return min + (value > range ? total - value : value);
837    });
838  },
839      _replaceRandom = function _replaceRandom(
vendor: 531 bytes, lines 839-855
839value) {
840    var prev = 0,
841        s = "",
842        i,
843        nums,
844        end,
845        isArray;
846
847    while (~(i = value.indexOf("random(", prev))) {
848      end = value.indexOf(")", i);
849      isArray = value.charAt(i + 7) === "[";
850      nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp);
851      s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5);
852      prev = end + 1;
853    }
854
855    return s + value.substr(prev, value.length - prev
vendor: 14,290 bytes, lines 855-1371
855);
856  },
857      mapRange = function mapRange(inMin, inMax, outMin, outMax, value) {
858    var inRange = inMax - inMin,
859        outRange = outMax - outMin;
860    return _conditionalReturn(value, function (value) {
861      return outMin + ((value - inMin) / inRange * outRange || 0);
862    });
863  },
864      interpolate = function interpolate(start, end, progress, mutate) {
865    var func = isNaN(start + end) ? 0 : function (p) {
866      return (1 - p) * start + p * end;
867    };
868
869    if (!func) {
870      var isString = _isString(start),
871          master = {},
872          p,
873          i,
874          interpolators,
875          l,
876          il;
877
878      progress === true && (mutate = 1) && (progress = null);
879
880      if (isString) {
881        start = {
882          p: start
883        };
884        end = {
885          p: end
886        };
887      } else if (_isArray(start) && !_isArray(end)) {
888        interpolators = [];
889        l = start.length;
890        il = l - 2;
891
892        for (i = 1; i < l; i++) {
893          interpolators.push(interpolate(start[i - 1], start[i]));
894        }
895
896        l--;
897
898        func = function func(p) {
899          p *= l;
900          var i = Math.min(il, ~~p);
901          return interpolators[i](p - i);
902        };
903
904        progress = end;
905      } else if (!mutate) {
906        start = _merge(_isArray(start) ? [] : {}, start);
907      }
908
909      if (!interpolators) {
910        for (p in end) {
911          _addPropTween.call(master, start, p, "get", end[p]);
912        }
913
914        func = function func(p) {
915          return _renderPropTweens(p, master) || (isString ? start.p : start);
916        };
917      }
918    }
919
920    return _conditionalReturn(progress, func);
921  },
922      _getLabelInDirection = function _getLabelInDirection(timeline, fromTime, backward) {
923    var labels = timeline.labels,
924        min = _bigNum,
925        p,
926        distance,
927        label;
928
929    for (p in labels) {
930      distance = labels[p] - fromTime;
931
932      if (distance < 0 === !!backward && distance && min > (distance = Math.abs(distance))) {
933        label = p;
934        min = distance;
935      }
936    }
937
938    return label;
939  },
940      _callback = function _callback(animation, type, executeLazyFirst) {
941    var v = animation.vars,
942        callback = v[type],
943        prevContext = _context,
944        context = animation._ctx,
945        params,
946        scope,
947        result;
948
949    if (!callback) {
950      return;
951    }
952
953    params = v[type + "Params"];
954    scope = v.callbackScope || animation;
955    executeLazyFirst && _lazyTweens.length && _lazyRender();
956    context && (_context = context);
957    result = params ? callback.apply(scope, params) : callback.call(scope);
958    _context = prevContext;
959    return result;
960  },
961      _interrupt = function _interrupt(animation) {
962    _removeFromParent(animation);
963
964    animation.scrollTrigger && animation.scrollTrigger.kill(!!_reverting);
965    animation.progress() < 1 && _callback(animation, "onInterrupt");
966    return animation;
967  },
968      _quickTween,
969      _registerPluginQueue = [],
970      _createPlugin = function _createPlugin(config) {
971    if (!config) return;
972    config = !config.name && config["default"] || config;
973
974    if (_windowExists() || config.headless) {
975      var name = config.name,
976          isFunc = _isFunction(config),
977          Plugin = name && !isFunc && config.init ? function () {
978        this._props = [];
979      } : config,
980          instanceDefaults = {
981        init: _emptyFunc,
982        render: _renderPropTweens,
983        add: _addPropTween,
984        kill: _killPropTweensOf,
985        modifier: _addPluginModifier,
986        rawVars: 0
987      },
988          statics = {
989        targetTest: 0,
990        get: 0,
991        getSetter: _getSetter,
992        aliases: {},
993        register: 0
994      };
995
996      _wake();
997
998      if (config !== Plugin) {
999        if (_plugins[name]) {
1000          return;
1001        }
1002
1003        _setDefaults(Plugin, _setDefaults(_copyExcluding(config, instanceDefaults), statics));
1004
1005        _merge(Plugin.prototype, _merge(instanceDefaults, _copyExcluding(config, statics)));
1006
1007        _plugins[Plugin.prop = name] = Plugin;
1008
1009        if (config.targetTest) {
1010          _harnessPlugins.push(Plugin);
1011
1012          _reservedProps[name] = 1;
1013        }
1014
1015        name = (name === "css" ? "CSS" : name.charAt(0).toUpperCase() + name.substr(1)) + "Plugin";
1016      }
1017
1018      _addGlobal(name, Plugin);
1019
1020      config.register && config.register(gsap, Plugin, PropTween);
1021    } else {
1022      _registerPluginQueue.push(config);
1023    }
1024  },
1025      _255 = 255,
1026      _colorLookup = {
1027    aqua: [0, _255, _255],
1028    lime: [0, _255, 0],
1029    silver: [192, 192, 192],
1030    black: [0, 0, 0],
1031    maroon: [128, 0, 0],
1032    teal: [0, 128, 128],
1033    blue: [0, 0, _255],
1034    navy: [0, 0, 128],
1035    white: [_255, _255, _255],
1036    olive: [128, 128, 0],
1037    yellow: [_255, _255, 0],
1038    orange: [_255, 165, 0],
1039    gray: [128, 128, 128],
1040    purple: [128, 0, 128],
1041    green: [0, 128, 0],
1042    red: [_255, 0, 0],
1043    pink: [_255, 192, 203],
1044    cyan: [0, _255, _255],
1045    transparent: [_255, _255, _255, 0]
1046  },
1047      _hue = function _hue(h, m1, m2) {
1048    h += h < 0 ? 1 : h > 1 ? -1 : 0;
1049    return (h * 6 < 1 ? m1 + (m2 - m1) * h * 6 : h < .5 ? m2 : h * 3 < 2 ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * _255 + .5 | 0;
1050  },
1051      splitColor = function splitColor(v, toHSL, forceAlpha) {
1052    var a = !v ? _colorLookup.black : _isNumber(v) ? [v >> 16, v >> 8 & _255, v & _255] : 0,
1053        r,
1054        g,
1055        b,
1056        h,
1057        s,
1058        l,
1059        max,
1060        min,
1061        d,
1062        wasHSL;
1063
1064    if (!a) {
1065      if (v.substr(-1) === ",") {
1066        v = v.substr(0, v.length - 1);
1067      }
1068
1069      if (_colorLookup[v]) {
1070        a = _colorLookup[v];
1071      } else if (v.charAt(0) === "#") {
1072        if (v.length < 6) {
1073          r = v.charAt(1);
1074          g = v.charAt(2);
1075          b = v.charAt(3);
1076          v = "#" + r + r + g + g + b + b + (v.length === 5 ? v.charAt(4) + v.charAt(4) : "");
1077        }
1078
1079        if (v.length === 9) {
1080          a = parseInt(v.substr(1, 6), 16);
1081          return [a >> 16, a >> 8 & _255, a & _255, parseInt(v.substr(7), 16) / 255];
1082        }
1083
1084        v = parseInt(v.substr(1), 16);
1085        a = [v >> 16, v >> 8 & _255, v & _255];
1086      } else if (v.substr(0, 3) === "hsl") {
1087        a = wasHSL = v.match(_strictNumExp);
1088
1089        if (!toHSL) {
1090          h = +a[0] % 360 / 360;
1091          s = +a[1] / 100;
1092          l = +a[2] / 100;
1093          g = l <= .5 ? l * (s + 1) : l + s - l * s;
1094          r = l * 2 - g;
1095          a.length > 3 && (a[3] *= 1);
1096          a[0] = _hue(h + 1 / 3, r, g);
1097          a[1] = _hue(h, r, g);
1098          a[2] = _hue(h - 1 / 3, r, g);
1099        } else if (~v.indexOf("=")) {
1100          a = v.match(_numExp);
1101          forceAlpha && a.length < 4 && (a[3] = 1);
1102          return a;
1103        }
1104      } else {
1105        a = v.match(_strictNumExp) || _colorLookup.transparent;
1106      }
1107
1108      a = a.map(Number);
1109    }
1110
1111    if (toHSL && !wasHSL) {
1112      r = a[0] / _255;
1113      g = a[1] / _255;
1114      b = a[2] / _255;
1115      max = Math.max(r, g, b);
1116      min = Math.min(r, g, b);
1117      l = (max + min) / 2;
1118
1119      if (max === min) {
1120        h = s = 0;
1121      } else {
1122        d = max - min;
1123        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1124        h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
1125        h *= 60;
1126      }
1127
1128      a[0] = ~~(h + .5);
1129      a[1] = ~~(s * 100 + .5);
1130      a[2] = ~~(l * 100 + .5);
1131    }
1132
1133    forceAlpha && a.length < 4 && (a[3] = 1);
1134    return a;
1135  },
1136      _colorOrderData = function _colorOrderData(v) {
1137    var values = [],
1138        c = [],
1139        i = -1;
1140    v.split(_colorExp).forEach(function (v) {
1141      var a = v.match(_numWithUnitExp) || [];
1142      values.push.apply(values, a);
1143      c.push(i += a.length + 1);
1144    });
1145    values.c = c;
1146    return values;
1147  },
1148      _formatColors = function _formatColors(s, toHSL, orderMatchData) {
1149    var result = "",
1150        colors = (s + result).match(_colorExp),
1151        type = toHSL ? "hsla(" : "rgba(",
1152        i = 0,
1153        c,
1154        shell,
1155        d,
1156        l;
1157
1158    if (!colors) {
1159      return s;
1160    }
1161
1162    colors = colors.map(function (color) {
1163      return (color = splitColor(color, toHSL, 1)) && type + (toHSL ? color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : color.join(",")) + ")";
1164    });
1165
1166    if (orderMatchData) {
1167      d = _colorOrderData(s);
1168      c = orderMatchData.c;
1169
1170      if (c.join(result) !== d.c.join(result)) {
1171        shell = s.replace(_colorExp, "1").split(_numWithUnitExp);
1172        l = shell.length - 1;
1173
1174        for (; i < l; i++) {
1175          result += shell[i] + (~c.indexOf(i) ? colors.shift() || type + "0,0,0,0)" : (d.length ? d : colors.length ? colors : orderMatchData).shift());
1176        }
1177      }
1178    }
1179
1180    if (!shell) {
1181      shell = s.split(_colorExp);
1182      l = shell.length - 1;
1183
1184      for (; i < l; i++) {
1185        result += shell[i] + colors[i];
1186      }
1187    }
1188
1189    return result + shell[l];
1190  },
1191      _colorExp = function () {
1192    var s = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#(?:[0-9a-f]{3,4}){1,2}\\b",
1193        p;
1194
1195    for (p in _colorLookup) {
1196      s += "|" + p + "\\b";
1197    }
1198
1199    return new RegExp(s + ")", "gi");
1200  }(),
1201      _hslExp = /hsl[a]?\(/,
1202      _colorStringFilter = function _colorStringFilter(a) {
1203    var combined = a.join(" "),
1204        toHSL;
1205    _colorExp.lastIndex = 0;
1206
1207    if (_colorExp.test(combined)) {
1208      toHSL = _hslExp.test(combined);
1209      a[1] = _formatColors(a[1], toHSL);
1210      a[0] = _formatColors(a[0], toHSL, _colorOrderData(a[1]));
1211      return true;
1212    }
1213  },
1214      _tickerActive,
1215      _ticker = function () {
1216    var _getTime = Date.now,
1217        _lagThreshold = 500,
1218        _adjustedLag = 33,
1219        _startTime = _getTime(),
1220        _lastUpdate = _startTime,
1221        _gap = 1000 / 240,
1222        _nextTime = _gap,
1223        _listeners = [],
1224        _id,
1225        _req,
1226        _raf,
1227        _self,
1228        _delta,
1229        _i,
1230        _tick = function _tick(v) {
1231      var elapsed = _getTime() - _lastUpdate,
1232          manual = v === true,
1233          overlap,
1234          dispatch,
1235          time,
1236          frame;
1237
1238      (elapsed > _lagThreshold || elapsed < 0) && (_startTime += elapsed - _adjustedLag);
1239      _lastUpdate += elapsed;
1240      time = _lastUpdate - _startTime;
1241      overlap = time - _nextTime;
1242
1243      if (overlap > 0 || manual) {
1244        frame = ++_self.frame;
1245        _delta = time - _self.time * 1000;
1246        _self.time = time = time / 1000;
1247        _nextTime += overlap + (overlap >= _gap ? 4 : _gap - overlap);
1248        dispatch = 1;
1249      }
1250
1251      manual || (_id = _req(_tick));
1252
1253      if (dispatch) {
1254        for (_i = 0; _i < _listeners.length; _i++) {
1255          _listeners[_i](time, _delta, frame, v);
1256        }
1257      }
1258    };
1259
1260    _self = {
1261      time: 0,
1262      frame: 0,
1263      tick: function tick() {
1264        _tick(true);
1265      },
1266      deltaRatio: function deltaRatio(fps) {
1267        return _delta / (1000 / (fps || 60));
1268      },
1269      wake: function wake() {
1270        if (_coreReady) {
1271          if (!_coreInitted && _windowExists()) {
1272            _win = _coreInitted = window;
1273            _doc = _win.document || {};
1274            _globals.gsap = gsap;
1275            (_win.gsapVersions || (_win.gsapVersions = [])).push(gsap.version);
1276
1277            _install(_installScope || _win.GreenSockGlobals || !_win.gsap && _win || {});
1278
1279            _registerPluginQueue.forEach(_createPlugin);
1280          }
1281
1282          _raf = typeof requestAnimationFrame !== "undefined" && requestAnimationFrame;
1283          _id && _self.sleep();
1284
1285          _req = _raf || function (f) {
1286            return setTimeout(f, _nextTime - _self.time * 1000 + 1 | 0);
1287          };
1288
1289          _tickerActive = 1;
1290
1291          _tick(2);
1292        }
1293      },
1294      sleep: function sleep() {
1295        (_raf ? cancelAnimationFrame : clearTimeout)(_id);
1296        _tickerActive = 0;
1297        _req = _emptyFunc;
1298      },
1299      lagSmoothing: function lagSmoothing(threshold, adjustedLag) {
1300        _lagThreshold = threshold || Infinity;
1301        _adjustedLag = Math.min(adjustedLag || 33, _lagThreshold);
1302      },
1303      fps: function fps(_fps) {
1304        _gap = 1000 / (_fps || 240);
1305        _nextTime = _self.time * 1000 + _gap;
1306      },
1307      add: function add(callback, once, prioritize) {
1308        var func = once ? function (t, d, f, v) {
1309          callback(t, d, f, v);
1310
1311          _self.remove(func);
1312        } : callback;
1313
1314        _self.remove(callback);
1315
1316        _listeners[prioritize ? "unshift" : "push"](func);
1317
1318        _wake();
1319
1320        return func;
1321      },
1322      remove: function remove(callback, i) {
1323        ~(i = _listeners.indexOf(callback)) && _listeners.splice(i, 1) && _i >= i && _i--;
1324      },
1325      _listeners: _listeners
1326    };
1327    return _self;
1328  }(),
1329      _wake = function _wake() {
1330    return !_tickerActive && _ticker.wake();
1331  },
1332      _easeMap = {},
1333      _customEaseExp = /^[\d.\-M][\d.\-,\s]/,
1334      _quotesExp = /["']/g,
1335      _parseObjectInString = function _parseObjectInString(value) {
1336    var obj = {},
1337        split = value.substr(1, value.length - 3).split(":"),
1338        key = split[0],
1339        i = 1,
1340        l = split.length,
1341        index,
1342        val,
1343        parsedVal;
1344
1345    for (; i < l; i++) {
1346      val = split[i];
1347      index = i !== l - 1 ? val.lastIndexOf(",") : val.length;
1348      parsedVal = val.substr(0, index);
1349      obj[key] = isNaN(parsedVal) ? parsedVal.replace(_quotesExp, "").trim() : +parsedVal;
1350      key = val.substr(index + 1).trim();
1351    }
1352
1353    return obj;
1354  },
1355      _valueInParentheses = function _valueInParentheses(value) {
1356    var open = value.indexOf("(") + 1,
1357        close = value.indexOf(")"),
1358        nested = value.indexOf("(", open);
1359    return value.substring(open, ~nested && nested < close ? value.indexOf(")", close + 1) : close);
1360  },
1361      _configEaseFromString = function _configEaseFromString(name) {
1362    var split = (name + "").split("("),
1363        ease = _easeMap[split[0]];
1364    return ease && split.length > 1 && ease.config ? ease.config.apply(null, ~name.indexOf("{") ? [_parseObjectInString(split[1])] : _valueInParentheses(name).split(",").map(_numericIfPossible)) : _easeMap._CE && _customEaseExp.test(name) ? _easeMap._CE("", name) : ease;
1365  },
1366      _invertEase = function _invertEase(ease) {
1367    return function (p) {
1368      return 1 - ease(1 - p);
1369    };
1370  },
1371      _p
1371ropagateYoyoEase = function _propagateYoyoEase(timeline, isYoyo) {
1372    var child = timeline._first,
1373        ease;
1374
1375    while (child) {
1376      if (child instanceof Timeline) {
1377        _propagateYoyoEase(child, isYoyo);
1378      } else if (child.vars.yoyoEase && (!child._yoyo || !child._repeat) && child._yoyo !== isYoyo) {
1379        if (child.timeline) {
1380          _propagateYoyoEase(child.timeline, isYoyo);
1381        } else {
1382          ease = child._ease;
1383          child._ease = child._yEase;
1384          child._yEase = ease;
1385          child._yoyo = isYoyo;
1386        }
1387      }
1388
1389      child = child._next;
1390    }
vendor: 3,445 bytes, lines 1390-1501
1390
1391  },
1392      _parseEase = function _parseEase(ease, defaultEase) {
1393    return !ease ? defaultEase : (_isFunction(ease) ? ease : _easeMap[ease] || _configEaseFromString(ease)) || defaultEase;
1394  },
1395      _insertEase = function _insertEase(names, easeIn, easeOut, easeInOut) {
1396    if (easeOut === void 0) {
1397      easeOut = function easeOut(p) {
1398        return 1 - easeIn(1 - p);
1399      };
1400    }
1401
1402    if (easeInOut === void 0) {
1403      easeInOut = function easeInOut(p) {
1404        return p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2;
1405      };
1406    }
1407
1408    var ease = {
1409      easeIn: easeIn,
1410      easeOut: easeOut,
1411      easeInOut: easeInOut
1412    },
1413        lowercaseName;
1414
1415    _forEachName(names, function (name) {
1416      _easeMap[name] = _globals[name] = ease;
1417      _easeMap[lowercaseName = name.toLowerCase()] = easeOut;
1418
1419      for (var p in ease) {
1420        _easeMap[lowercaseName + (p === "easeIn" ? ".in" : p === "easeOut" ? ".out" : ".inOut")] = _easeMap[name + "." + p] = ease[p];
1421      }
1422    });
1423
1424    return ease;
1425  },
1426      _easeInOutFromOut = function _easeInOutFromOut(easeOut) {
1427    return function (p) {
1428      return p < .5 ? (1 - easeOut(1 - p * 2)) / 2 : .5 + easeOut((p - .5) * 2) / 2;
1429    };
1430  },
1431      _configElastic = function _configElastic(type, amplitude, period) {
1432    var p1 = amplitude >= 1 ? amplitude : 1,
1433        p2 = (period || (type ? .3 : .45)) / (amplitude < 1 ? amplitude : 1),
1434        p3 = p2 / _2PI * (Math.asin(1 / p1) || 0),
1435        easeOut = function easeOut(p) {
1436      return p === 1 ? 1 : p1 * Math.pow(2, -10 * p) * _sin((p - p3) * p2) + 1;
1437    },
1438        ease = type === "out" ? easeOut : type === "in" ? function (p) {
1439      return 1 - easeOut(1 - p);
1440    } : _easeInOutFromOut(easeOut);
1441
1442    p2 = _2PI / p2;
1443
1444    ease.config = function (amplitude, period) {
1445      return _configElastic(type, amplitude, period);
1446    };
1447
1448    return ease;
1449  },
1450      _configBack = function _configBack(type, overshoot) {
1451    if (overshoot === void 0) {
1452      overshoot = 1.70158;
1453    }
1454
1455    var easeOut = function easeOut(p) {
1456      return p ? --p * p * ((overshoot + 1) * p + overshoot) + 1 : 0;
1457    },
1458        ease = type === "out" ? easeOut : type === "in" ? function (p) {
1459      return 1 - easeOut(1 - p);
1460    } : _easeInOutFromOut(easeOut);
1461
1462    ease.config = function (overshoot) {
1463      return _configBack(type, overshoot);
1464    };
1465
1466    return ease;
1467  };
1468
1469  _forEachName("Linear,Quad,Cubic,Quart,Quint,Strong", function (name, i) {
1470    var power = i < 5 ? i + 1 : i;
1471
1472    _insertEase(name + ",Power" + (power - 1), i ? function (p) {
1473      return Math.pow(p, power);
1474    } : function (p) {
1475      return p;
1476    }, function (p) {
1477      return 1 - Math.pow(1 - p, power);
1478    }, function (p) {
1479      return p < .5 ? Math.pow(p * 2, power) / 2 : 1 - Math.pow((1 - p) * 2, power) / 2;
1480    });
1481  });
1482
1483  _easeMap.Linear.easeNone = _easeMap.none = _easeMap.Linear.easeIn;
1484
1485  _insertEase("Elastic", _configElastic("in"), _configElastic("out"), _configElastic());
1486
1487  (function (n, c) {
1488    var n1 = 1 / c,
1489        n2 = 2 * n1,
1490        n3 = 2.5 * n1,
1491        easeOut = function easeOut(p) {
1492      return p < n1 ? n * p * p : p < n2 ? n * Math.pow(p - 1.5 / c, 2) + .75 : p < n3 ? n * (p -= 2.25 / c) * p + .9375 : n * Math.pow(p - 2.625 / c, 2) + .984375;
1493    };
1494
1495    _insertEase("Bounce", function (p) {
1496      return 1 - easeOut(1 - p);
1497    }, easeOut);
1498  })(7.5625, 2.75);
1499
1500  _insertEase("Expo", function (p) {
1501    return 
vendor: 18,509 bytes, lines 1501-2076
1501p ? Math.pow(2, 10 * (p - 1)) : 0;
1502  });
1503
1504  _insertEase("Circ", function (p) {
1505    return -(_sqrt(1 - p * p) - 1);
1506  });
1507
1508  _insertEase("Sine", function (p) {
1509    return p === 1 ? 1 : -_cos(p * _HALF_PI) + 1;
1510  });
1511
1512  _insertEase("Back", _configBack("in"), _configBack("out"), _configBack());
1513
1514  _easeMap.SteppedEase = _easeMap.steps = _globals.SteppedEase = {
1515    config: function config(steps, immediateStart) {
1516      if (steps === void 0) {
1517        steps = 1;
1518      }
1519
1520      var p1 = 1 / steps,
1521          p2 = steps + (immediateStart ? 0 : 1),
1522          p3 = immediateStart ? 1 : 0,
1523          max = 1 - _tinyNum;
1524      return function (p) {
1525        return ((p2 * _clamp(0, max, p) | 0) + p3) * p1;
1526      };
1527    }
1528  };
1529  _defaults.ease = _easeMap["quad.out"];
1530
1531  _forEachName("onComplete,onUpdate,onStart,onRepeat,onReverseComplete,onInterrupt", function (name) {
1532    return _callbackNames += name + "," + name + "Params,";
1533  });
1534
1535  var GSCache = function GSCache(target, harness) {
1536    this.id = _gsID++;
1537    target._gsap = this;
1538    this.target = target;
1539    this.harness = harness;
1540    this.get = harness ? harness.get : _getProperty;
1541    this.set = harness ? harness.getSetter : _getSetter;
1542  };
1543  var Animation = function () {
1544    function Animation(vars) {
1545      this.vars = vars;
1546      this._delay = +vars.delay || 0;
1547
1548      if (this._repeat = vars.repeat === Infinity ? -2 : vars.repeat || 0) {
1549        this._rDelay = vars.repeatDelay || 0;
1550        this._yoyo = !!vars.yoyo || !!vars.yoyoEase;
1551      }
1552
1553      this._ts = 1;
1554
1555      _setDuration(this, +vars.duration, 1, 1);
1556
1557      this.data = vars.data;
1558
1559      if (_context) {
1560        this._ctx = _context;
1561
1562        _context.data.push(this);
1563      }
1564
1565      _tickerActive || _ticker.wake();
1566    }
1567
1568    var _proto = Animation.prototype;
1569
1570    _proto.delay = function delay(value) {
1571      if (value || value === 0) {
1572        this.parent && this.parent.smoothChildTiming && this.startTime(this._start + value - this._delay);
1573        this._delay = value;
1574        return this;
1575      }
1576
1577      return this._delay;
1578    };
1579
1580    _proto.duration = function duration(value) {
1581      return arguments.length ? this.totalDuration(this._repeat > 0 ? value + (value + this._rDelay) * this._repeat : value) : this.totalDuration() && this._dur;
1582    };
1583
1584    _proto.totalDuration = function totalDuration(value) {
1585      if (!arguments.length) {
1586        return this._tDur;
1587      }
1588
1589      this._dirty = 0;
1590      return _setDuration(this, this._repeat < 0 ? value : (value - this._repeat * this._rDelay) / (this._repeat + 1));
1591    };
1592
1593    _proto.totalTime = function totalTime(_totalTime, suppressEvents) {
1594      _wake();
1595
1596      if (!arguments.length) {
1597        return this._tTime;
1598      }
1599
1600      var parent = this._dp;
1601
1602      if (parent && parent.smoothChildTiming && this._ts) {
1603        _alignPlayhead(this, _totalTime);
1604
1605        !parent._dp || parent.parent || _postAddChecks(parent, this);
1606
1607        while (parent && parent.parent) {
1608          if (parent.parent._time !== parent._start + (parent._ts >= 0 ? parent._tTime / parent._ts : (parent.totalDuration() - parent._tTime) / -parent._ts)) {
1609            parent.totalTime(parent._tTime, true);
1610          }
1611
1612          parent = parent.parent;
1613        }
1614
1615        if (!this.parent && this._dp.autoRemoveChildren && (this._ts > 0 && _totalTime < this._tDur || this._ts < 0 && _totalTime > 0 || !this._tDur && !_totalTime)) {
1616          _addToTimeline(this._dp, this, this._start - this._delay);
1617        }
1618      }
1619
1620      if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !_totalTime && !this._initted && (this.add || this._ptLookup)) {
1621        this._ts || (this._pTime = _totalTime);
1622
1623        _lazySafeRender(this, _totalTime, suppressEvents);
1624      }
1625
1626      return this;
1627    };
1628
1629    _proto.time = function time(value, suppressEvents) {
1630      return arguments.length ? this.totalTime(Math.min(this.totalDuration(), value + _elapsedCycleDuration(this)) % (this._dur + this._rDelay) || (value ? this._dur : 0), suppressEvents) : this._time;
1631    };
1632
1633    _proto.totalProgress = function totalProgress(value, suppressEvents) {
1634      return arguments.length ? this.totalTime(this.totalDuration() * value, suppressEvents) : this.totalDuration() ? Math.min(1, this._tTime / this._tDur) : this.rawTime() > 0 ? 1 : 0;
1635    };
1636
1637    _proto.progress = function progress(value, suppressEvents) {
1638      return arguments.length ? this.totalTime(this.duration() * (this._yoyo && !(this.iteration() & 1) ? 1 - value : value) + _elapsedCycleDuration(this), suppressEvents) : this.duration() ? Math.min(1, this._time / this._dur) : this.rawTime() > 0 ? 1 : 0;
1639    };
1640
1641    _proto.iteration = function iteration(value, suppressEvents) {
1642      var cycleDuration = this.duration() + this._rDelay;
1643
1644      return arguments.length ? this.totalTime(this._time + (value - 1) * cycleDuration, suppressEvents) : this._repeat ? _animationCycle(this._tTime, cycleDuration) + 1 : 1;
1645    };
1646
1647    _proto.timeScale = function timeScale(value, suppressEvents) {
1648      if (!arguments.length) {
1649        return this._rts === -_tinyNum ? 0 : this._rts;
1650      }
1651
1652      if (this._rts === value) {
1653        return this;
1654      }
1655
1656      var tTime = this.parent && this._ts ? _parentToChildTotalTime(this.parent._time, this) : this._tTime;
1657      this._rts = +value || 0;
1658      this._ts = this._ps || value === -_tinyNum ? 0 : this._rts;
1659      this.totalTime(_clamp(-Math.abs(this._delay), this._tDur, tTime), suppressEvents !== false);
1660
1661      _setEnd(this);
1662
1663      return _recacheAncestors(this);
1664    };
1665
1666    _proto.paused = function paused(value) {
1667      if (!arguments.length) {
1668        return this._ps;
1669      }
1670
1671      if (this._ps !== value) {
1672        this._ps = value;
1673
1674        if (value) {
1675          this._pTime = this._tTime || Math.max(-this._delay, this.rawTime());
1676          this._ts = this._act = 0;
1677        } else {
1678          _wake();
1679
1680          this._ts = this._rts;
1681          this.totalTime(this.parent && !this.parent.smoothChildTiming ? this.rawTime() : this._tTime || this._pTime, this.progress() === 1 && Math.abs(this._zTime) !== _tinyNum && (this._tTime -= _tinyNum));
1682        }
1683      }
1684
1685      return this;
1686    };
1687
1688    _proto.startTime = function startTime(value) {
1689      if (arguments.length) {
1690        this._start = value;
1691        var parent = this.parent || this._dp;
1692        parent && (parent._sort || !this.parent) && _addToTimeline(parent, this, value - this._delay);
1693        return this;
1694      }
1695
1696      return this._start;
1697    };
1698
1699    _proto.endTime = function endTime(includeRepeats) {
1700      return this._start + (_isNotFalse(includeRepeats) ? this.totalDuration() : this.duration()) / Math.abs(this._ts || 1);
1701    };
1702
1703    _proto.rawTime = function rawTime(wrapRepeats) {
1704      var parent = this.parent || this._dp;
1705      return !parent ? this._tTime : wrapRepeats && (!this._ts || this._repeat && this._time && this.totalProgress() < 1) ? this._tTime % (this._dur + this._rDelay) : !this._ts ? this._tTime : _parentToChildTotalTime(parent.rawTime(wrapRepeats), this);
1706    };
1707
1708    _proto.revert = function revert(config) {
1709      if (config === void 0) {
1710        config = _revertConfig;
1711      }
1712
1713      var prevIsReverting = _reverting;
1714      _reverting = config;
1715
1716      if (this._initted || this._startAt) {
1717        this.timeline && this.timeline.revert(config);
1718        this.totalTime(-0.01, config.suppressEvents);
1719      }
1720
1721      this.data !== "nested" && config.kill !== false && this.kill();
1722      _reverting = prevIsReverting;
1723      return this;
1724    };
1725
1726    _proto.globalTime = function globalTime(rawTime) {
1727      var animation = this,
1728          time = arguments.length ? rawTime : animation.rawTime();
1729
1730      while (animation) {
1731        time = animation._start + time / (Math.abs(animation._ts) || 1);
1732        animation = animation._dp;
1733      }
1734
1735      return !this.parent && this._sat ? this._sat.globalTime(rawTime) : time;
1736    };
1737
1738    _proto.repeat = function repeat(value) {
1739      if (arguments.length) {
1740        this._repeat = value === Infinity ? -2 : value;
1741        return _onUpdateTotalDuration(this);
1742      }
1743
1744      return this._repeat === -2 ? Infinity : this._repeat;
1745    };
1746
1747    _proto.repeatDelay = function repeatDelay(value) {
1748      if (arguments.length) {
1749        var time = this._time;
1750        this._rDelay = value;
1751
1752        _onUpdateTotalDuration(this);
1753
1754        return time ? this.time(time) : this;
1755      }
1756
1757      return this._rDelay;
1758    };
1759
1760    _proto.yoyo = function yoyo(value) {
1761      if (arguments.length) {
1762        this._yoyo = value;
1763        return this;
1764      }
1765
1766      return this._yoyo;
1767    };
1768
1769    _proto.seek = function seek(position, suppressEvents) {
1770      return this.totalTime(_parsePosition(this, position), _isNotFalse(suppressEvents));
1771    };
1772
1773    _proto.restart = function restart(includeDelay, suppressEvents) {
1774      return this.play().totalTime(includeDelay ? -this._delay : 0, _isNotFalse(suppressEvents));
1775    };
1776
1777    _proto.play = function play(from, suppressEvents) {
1778      from != null && this.seek(from, suppressEvents);
1779      return this.reversed(false).paused(false);
1780    };
1781
1782    _proto.reverse = function reverse(from, suppressEvents) {
1783      from != null && this.seek(from || this.totalDuration(), suppressEvents);
1784      return this.reversed(true).paused(false);
1785    };
1786
1787    _proto.pause = function pause(atTime, suppressEvents) {
1788      atTime != null && this.seek(atTime, suppressEvents);
1789      return this.paused(true);
1790    };
1791
1792    _proto.resume = function resume() {
1793      return this.paused(false);
1794    };
1795
1796    _proto.reversed = function reversed(value) {
1797      if (arguments.length) {
1798        !!value !== this.reversed() && this.timeScale(-this._rts || (value ? -_tinyNum : 0));
1799        return this;
1800      }
1801
1802      return this._rts < 0;
1803    };
1804
1805    _proto.invalidate = function invalidate() {
1806      this._initted = this._act = 0;
1807      this._zTime = -_tinyNum;
1808      return this;
1809    };
1810
1811    _proto.isActive = function isActive() {
1812      var parent = this.parent || this._dp,
1813          start = this._start,
1814          rawTime;
1815      return !!(!parent || this._ts && this._initted && parent.isActive() && (rawTime = parent.rawTime(true)) >= start && rawTime < this.endTime(true) - _tinyNum);
1816    };
1817
1818    _proto.eventCallback = function eventCallback(type, callback, params) {
1819      var vars = this.vars;
1820
1821      if (arguments.length > 1) {
1822        if (!callback) {
1823          delete vars[type];
1824        } else {
1825          vars[type] = callback;
1826          params && (vars[type + "Params"] = params);
1827          type === "onUpdate" && (this._onUpdate = callback);
1828        }
1829
1830        return this;
1831      }
1832
1833      return vars[type];
1834    };
1835
1836    _proto.then = function then(onFulfilled) {
1837      var self = this;
1838      return new Promise(function (resolve) {
1839        var f = _isFunction(onFulfilled) ? onFulfilled : _passThrough,
1840            _resolve = function _resolve() {
1841          var _then = self.then;
1842          self.then = null;
1843          _isFunction(f) && (f = f(self)) && (f.then || f === self) && (self.then = _then);
1844          resolve(f);
1845          self.then = _then;
1846        };
1847
1848        if (self._initted && self.totalProgress() === 1 && self._ts >= 0 || !self._tTime && self._ts < 0) {
1849          _resolve();
1850        } else {
1851          self._prom = _resolve;
1852        }
1853      });
1854    };
1855
1856    _proto.kill = function kill() {
1857      _interrupt(this);
1858    };
1859
1860    return Animation;
1861  }();
1862
1863  _setDefaults(Animation.prototype, {
1864    _time: 0,
1865    _start: 0,
1866    _end: 0,
1867    _tTime: 0,
1868    _tDur: 0,
1869    _dirty: 0,
1870    _repeat: 0,
1871    _yoyo: false,
1872    parent: null,
1873    _initted: false,
1874    _rDelay: 0,
1875    _ts: 1,
1876    _dp: 0,
1877    ratio: 0,
1878    _zTime: -_tinyNum,
1879    _prom: 0,
1880    _ps: false,
1881    _rts: 1
1882  });
1883
1884  var Timeline = function (_Animation) {
1885    _inheritsLoose(Timeline, _Animation);
1886
1887    function Timeline(vars, position) {
1888      var _this;
1889
1890      if (vars === void 0) {
1891        vars = {};
1892      }
1893
1894      _this = _Animation.call(this, vars) || this;
1895      _this.labels = {};
1896      _this.smoothChildTiming = !!vars.smoothChildTiming;
1897      _this.autoRemoveChildren = !!vars.autoRemoveChildren;
1898      _this._sort = _isNotFalse(vars.sortChildren);
1899      _globalTimeline && _addToTimeline(vars.parent || _globalTimeline, _assertThisInitialized(_this), position);
1900      vars.reversed && _this.reverse();
1901      vars.paused && _this.paused(true);
1902      vars.scrollTrigger && _scrollTrigger(_assertThisInitialized(_this), vars.scrollTrigger);
1903      return _this;
1904    }
1905
1906    var _proto2 = Timeline.prototype;
1907
1908    _proto2.to = function to(targets, vars, position) {
1909      _createTweenType(0, arguments, this);
1910
1911      return this;
1912    };
1913
1914    _proto2.from = function from(targets, vars, position) {
1915      _createTweenType(1, arguments, this);
1916
1917      return this;
1918    };
1919
1920    _proto2.fromTo = function fromTo(targets, fromVars, toVars, position) {
1921      _createTweenType(2, arguments, this);
1922
1923      return this;
1924    };
1925
1926    _proto2.set = function set(targets, vars, position) {
1927      vars.duration = 0;
1928      vars.parent = this;
1929      _inheritDefaults(vars).repeatDelay || (vars.repeat = 0);
1930      vars.immediateRender = !!vars.immediateRender;
1931      new Tween(targets, vars, _parsePosition(this, position), 1);
1932      return this;
1933    };
1934
1935    _proto2.call = function call(callback, params, position) {
1936      return _addToTimeline(this, Tween.delayedCall(0, callback, params), position);
1937    };
1938
1939    _proto2.staggerTo = function staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {
1940      vars.duration = duration;
1941      vars.stagger = vars.stagger || stagger;
1942      vars.onComplete = onCompleteAll;
1943      vars.onCompleteParams = onCompleteAllParams;
1944      vars.parent = this;
1945      new Tween(targets, vars, _parsePosition(this, position));
1946      return this;
1947    };
1948
1949    _proto2.staggerFrom = function staggerFrom(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {
1950      vars.runBackwards = 1;
1951      _inheritDefaults(vars).immediateRender = _isNotFalse(vars.immediateRender);
1952      return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams);
1953    };
1954
1955    _proto2.staggerFromTo = function staggerFromTo(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams) {
1956      toVars.startAt = fromVars;
1957      _inheritDefaults(toVars).immediateRender = _isNotFalse(toVars.immediateRender);
1958      return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams);
1959    };
1960
1961    _proto2.render = function render(totalTime, suppressEvents, force) {
1962      var prevTime = this._time,
1963          tDur = this._dirty ? this.totalDuration() : this._tDur,
1964          dur = this._dur,
1965          tTime = totalTime <= 0 ? 0 : _roundPrecise(totalTime),
1966          crossingStart = this._zTime < 0 !== totalTime < 0 && (this._initted || !dur),
1967          time,
1968          child,
1969          next,
1970          iteration,
1971          cycleDuration,
1972          prevPaused,
1973          pauseTween,
1974          timeScale,
1975          prevStart,
1976          prevIteration,
1977          yoyo,
1978          isYoyo;
1979      this !== _globalTimeline && tTime > tDur && totalTime >= 0 && (tTime = tDur);
1980
1981      if (tTime !== this._tTime || force || crossingStart) {
1982        if (prevTime !== this._time && dur) {
1983          tTime += this._time - prevTime;
1984          totalTime += this._time - prevTime;
1985        }
1986
1987        time = tTime;
1988        prevStart = this._start;
1989        timeScale = this._ts;
1990        prevPaused = !timeScale;
1991
1992        if (crossingStart) {
1993          dur || (prevTime = this._zTime);
1994          (totalTime || !suppressEvents) && (this._zTime = totalTime);
1995        }
1996
1997        if (this._repeat) {
1998          yoyo = this._yoyo;
1999          cycleDuration = dur + this._rDelay;
2000
2001          if (this._repeat < -1 && totalTime < 0) {
2002            return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);
2003          }
2004
2005          time = _roundPrecise(tTime % cycleDuration);
2006
2007          if (tTime === tDur) {
2008            iteration = this._repeat;
2009            time = dur;
2010          } else {
2011            iteration = ~~(tTime / cycleDuration);
2012
2013            if (iteration && iteration === tTime / cycleDuration) {
2014              time = dur;
2015              iteration--;
2016            }
2017
2018            time > dur && (time = dur);
2019          }
2020
2021          prevIteration = _animationCycle(this._tTime, cycleDuration);
2022          !prevTime && this._tTime && prevIteration !== iteration && this._tTime - prevIteration * cycleDuration - this._dur <= 0 && (prevIteration = iteration);
2023
2024          if (yoyo && iteration & 1) {
2025            time = dur - time;
2026            isYoyo = 1;
2027          }
2028
2029          if (iteration !== prevIteration && !this._lock) {
2030            var rewinding = yoyo && prevIteration & 1,
2031                doesWrap = rewinding === (yoyo && iteration & 1);
2032            iteration < prevIteration && (rewinding = !rewinding);
2033            prevTime = rewinding ? 0 : tTime % dur ? dur : tTime;
2034            this._lock = 1;
2035            this.render(prevTime || (isYoyo ? 0 : _roundPrecise(iteration * cycleDuration)), suppressEvents, !dur)._lock = 0;
2036            this._tTime = tTime;
2037            !suppressEvents && this.parent && _callback(this, "onRepeat");
2038            this.vars.repeatRefresh && !isYoyo && (this.invalidate()._lock = 1);
2039
2040            if (prevTime && prevTime !== this._time || prevPaused !== !this._ts || this.vars.onRepeat && !this.parent && !this._act) {
2041              return this;
2042            }
2043
2044            dur = this._dur;
2045            tDur = this._tDur;
2046
2047            if (doesWrap) {
2048              this._lock = 2;
2049              prevTime = rewinding ? dur : -0.0001;
2050              this.render(prevTime, true);
2051              this.vars.repeatRefresh && !isYoyo && this.invalidate();
2052            }
2053
2054            this._lock = 0;
2055
2056            if (!this._ts && !prevPaused) {
2057              return this;
2058            }
2059
2060            _propagateYoyoEase(this, isYoyo);
2061          }
2062        }
2063
2064        if (this._hasPause && !this._forcing && this._lock < 2) {
2065          pauseTween = _findNextPauseTween(this, _roundPrecise(prevTime), _roundPrecise(time));
2066
2067          if (pauseTween) {
2068            tTime -= time - (time = pauseTween._start);
2069          }
2070        }
2071
2072        this._tTime = tTime;
2073        this._time = time;
2074        this._act = !timeScale;
2075
2076        if (!this._initted) {
vendor: 30,026 bytes, lines 2077-3039
2077          this._onUpdate = this.vars.onUpdate;
2078          this._initted = 1;
2079          this._zTime = totalTime;
2080          prevTime = 0;
2081        }
2082
2083        if (!prevTime && time && !suppressEvents && !iteration) {
2084          _callback(this, "onStart");
2085
2086          if (this._tTime !== tTime) {
2087            return this;
2088          }
2089        }
2090
2091        if (time >= prevTime && totalTime >= 0) {
2092          child = this._first;
2093
2094          while (child) {
2095            next = child._next;
2096
2097            if ((child._act || time >= child._start) && child._ts && pauseTween !== child) {
2098              if (child.parent !== this) {
2099                return this.render(totalTime, suppressEvents, force);
2100              }
2101
2102              child.render(child._ts > 0 ? (time - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (time - child._start) * child._ts, suppressEvents, force);
2103
2104              if (time !== this._time || !this._ts && !prevPaused) {
2105                pauseTween = 0;
2106                next && (tTime += this._zTime = -_tinyNum);
2107                break;
2108              }
2109            }
2110
2111            child = next;
2112          }
2113        } else {
2114          child = this._last;
2115          var adjustedTime = totalTime < 0 ? totalTime : time;
2116
2117          while (child) {
2118            next = child._prev;
2119
2120            if ((child._act || adjustedTime <= child._end) && child._ts && pauseTween !== child) {
2121              if (child.parent !== this) {
2122                return this.render(totalTime, suppressEvents, force);
2123              }
2124
2125              child.render(child._ts > 0 ? (adjustedTime - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (adjustedTime - child._start) * child._ts, suppressEvents, force || _reverting && (child._initted || child._startAt));
2126
2127              if (time !== this._time || !this._ts && !prevPaused) {
2128                pauseTween = 0;
2129                next && (tTime += this._zTime = adjustedTime ? -_tinyNum : _tinyNum);
2130                break;
2131              }
2132            }
2133
2134            child = next;
2135          }
2136        }
2137
2138        if (pauseTween && !suppressEvents) {
2139          this.pause();
2140          pauseTween.render(time >= prevTime ? 0 : -_tinyNum)._zTime = time >= prevTime ? 1 : -1;
2141
2142          if (this._ts) {
2143            this._start = prevStart;
2144
2145            _setEnd(this);
2146
2147            return this.render(totalTime, suppressEvents, force);
2148          }
2149        }
2150
2151        this._onUpdate && !suppressEvents && _callback(this, "onUpdate", true);
2152        if (tTime === tDur && this._tTime >= this.totalDuration() || !tTime && prevTime) if (prevStart === this._start || Math.abs(timeScale) !== Math.abs(this._ts)) if (!this._lock) {
2153          (totalTime || !dur) && (tTime === tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1);
2154
2155          if (!suppressEvents && !(totalTime < 0 && !prevTime) && (tTime || prevTime || !tDur)) {
2156            _callback(this, tTime === tDur && totalTime >= 0 ? "onComplete" : "onReverseComplete", true);
2157
2158            this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();
2159          }
2160        }
2161      }
2162
2163      return this;
2164    };
2165
2166    _proto2.add = function add(child, position) {
2167      var _this2 = this;
2168
2169      _isNumber(position) || (position = _parsePosition(this, position, child));
2170
2171      if (!(child instanceof Animation)) {
2172        if (_isArray(child)) {
2173          child.forEach(function (obj) {
2174            return _this2.add(obj, position);
2175          });
2176          return this;
2177        }
2178
2179        if (_isString(child)) {
2180          return this.addLabel(child, position);
2181        }
2182
2183        if (_isFunction(child)) {
2184          child = Tween.delayedCall(0, child);
2185        } else {
2186          return this;
2187        }
2188      }
2189
2190      return this !== child ? _addToTimeline(this, child, position) : this;
2191    };
2192
2193    _proto2.getChildren = function getChildren(nested, tweens, timelines, ignoreBeforeTime) {
2194      if (nested === void 0) {
2195        nested = true;
2196      }
2197
2198      if (tweens === void 0) {
2199        tweens = true;
2200      }
2201
2202      if (timelines === void 0) {
2203        timelines = true;
2204      }
2205
2206      if (ignoreBeforeTime === void 0) {
2207        ignoreBeforeTime = -_bigNum;
2208      }
2209
2210      var a = [],
2211          child = this._first;
2212
2213      while (child) {
2214        if (child._start >= ignoreBeforeTime) {
2215          if (child instanceof Tween) {
2216            tweens && a.push(child);
2217          } else {
2218            timelines && a.push(child);
2219            nested && a.push.apply(a, child.getChildren(true, tweens, timelines));
2220          }
2221        }
2222
2223        child = child._next;
2224      }
2225
2226      return a;
2227    };
2228
2229    _proto2.getById = function getById(id) {
2230      var animations = this.getChildren(1, 1, 1),
2231          i = animations.length;
2232
2233      while (i--) {
2234        if (animations[i].vars.id === id) {
2235          return animations[i];
2236        }
2237      }
2238    };
2239
2240    _proto2.remove = function remove(child) {
2241      if (_isString(child)) {
2242        return this.removeLabel(child);
2243      }
2244
2245      if (_isFunction(child)) {
2246        return this.killTweensOf(child);
2247      }
2248
2249      _removeLinkedListItem(this, child);
2250
2251      if (child === this._recent) {
2252        this._recent = this._last;
2253      }
2254
2255      return _uncache(this);
2256    };
2257
2258    _proto2.totalTime = function totalTime(_totalTime2, suppressEvents) {
2259      if (!arguments.length) {
2260        return this._tTime;
2261      }
2262
2263      this._forcing = 1;
2264
2265      if (!this._dp && this._ts) {
2266        this._start = _roundPrecise(_ticker.time - (this._ts > 0 ? _totalTime2 / this._ts : (this.totalDuration() - _totalTime2) / -this._ts));
2267      }
2268
2269      _Animation.prototype.totalTime.call(this, _totalTime2, suppressEvents);
2270
2271      this._forcing = 0;
2272      return this;
2273    };
2274
2275    _proto2.addLabel = function addLabel(label, position) {
2276      this.labels[label] = _parsePosition(this, position);
2277      return this;
2278    };
2279
2280    _proto2.removeLabel = function removeLabel(label) {
2281      delete this.labels[label];
2282      return this;
2283    };
2284
2285    _proto2.addPause = function addPause(position, callback, params) {
2286      var t = Tween.delayedCall(0, callback || _emptyFunc, params);
2287      t.data = "isPause";
2288      this._hasPause = 1;
2289      return _addToTimeline(this, t, _parsePosition(this, position));
2290    };
2291
2292    _proto2.removePause = function removePause(position) {
2293      var child = this._first;
2294      position = _parsePosition(this, position);
2295
2296      while (child) {
2297        if (child._start === position && child.data === "isPause") {
2298          _removeFromParent(child);
2299        }
2300
2301        child = child._next;
2302      }
2303    };
2304
2305    _proto2.killTweensOf = function killTweensOf(targets, props, onlyActive) {
2306      var tweens = this.getTweensOf(targets, onlyActive),
2307          i = tweens.length;
2308
2309      while (i--) {
2310        _overwritingTween !== tweens[i] && tweens[i].kill(targets, props);
2311      }
2312
2313      return this;
2314    };
2315
2316    _proto2.getTweensOf = function getTweensOf(targets, onlyActive) {
2317      var a = [],
2318          parsedTargets = toArray(targets),
2319          child = this._first,
2320          isGlobalTime = _isNumber(onlyActive),
2321          children;
2322
2323      while (child) {
2324        if (child instanceof Tween) {
2325          if (_arrayContainsAny(child._targets, parsedTargets) && (isGlobalTime ? (!_overwritingTween || child._initted && child._ts) && child.globalTime(0) <= onlyActive && child.globalTime(child.totalDuration()) > onlyActive : !onlyActive || child.isActive())) {
2326            a.push(child);
2327          }
2328        } else if ((children = child.getTweensOf(parsedTargets, onlyActive)).length) {
2329          a.push.apply(a, children);
2330        }
2331
2332        child = child._next;
2333      }
2334
2335      return a;
2336    };
2337
2338    _proto2.tweenTo = function tweenTo(position, vars) {
2339      vars = vars || {};
2340
2341      var tl = this,
2342          endTime = _parsePosition(tl, position),
2343          _vars = vars,
2344          startAt = _vars.startAt,
2345          _onStart = _vars.onStart,
2346          onStartParams = _vars.onStartParams,
2347          immediateRender = _vars.immediateRender,
2348          initted,
2349          tween = Tween.to(tl, _setDefaults({
2350        ease: vars.ease || "none",
2351        lazy: false,
2352        immediateRender: false,
2353        time: endTime,
2354        overwrite: "auto",
2355        duration: vars.duration || Math.abs((endTime - (startAt && "time" in startAt ? startAt.time : tl._time)) / tl.timeScale()) || _tinyNum,
2356        onStart: function onStart() {
2357          tl.pause();
2358
2359          if (!initted) {
2360            var duration = vars.duration || Math.abs((endTime - (startAt && "time" in startAt ? startAt.time : tl._time)) / tl.timeScale());
2361            tween._dur !== duration && _setDuration(tween, duration, 0, 1).render(tween._time, true, true);
2362            initted = 1;
2363          }
2364
2365          _onStart && _onStart.apply(tween, onStartParams || []);
2366        }
2367      }, vars));
2368
2369      return immediateRender ? tween.render(0) : tween;
2370    };
2371
2372    _proto2.tweenFromTo = function tweenFromTo(fromPosition, toPosition, vars) {
2373      return this.tweenTo(toPosition, _setDefaults({
2374        startAt: {
2375          time: _parsePosition(this, fromPosition)
2376        }
2377      }, vars));
2378    };
2379
2380    _proto2.recent = function recent() {
2381      return this._recent;
2382    };
2383
2384    _proto2.nextLabel = function nextLabel(afterTime) {
2385      if (afterTime === void 0) {
2386        afterTime = this._time;
2387      }
2388
2389      return _getLabelInDirection(this, _parsePosition(this, afterTime));
2390    };
2391
2392    _proto2.previousLabel = function previousLabel(beforeTime) {
2393      if (beforeTime === void 0) {
2394        beforeTime = this._time;
2395      }
2396
2397      return _getLabelInDirection(this, _parsePosition(this, beforeTime), 1);
2398    };
2399
2400    _proto2.currentLabel = function currentLabel(value) {
2401      return arguments.length ? this.seek(value, true) : this.previousLabel(this._time + _tinyNum);
2402    };
2403
2404    _proto2.shiftChildren = function shiftChildren(amount, adjustLabels, ignoreBeforeTime) {
2405      if (ignoreBeforeTime === void 0) {
2406        ignoreBeforeTime = 0;
2407      }
2408
2409      var child = this._first,
2410          labels = this.labels,
2411          p;
2412
2413      while (child) {
2414        if (child._start >= ignoreBeforeTime) {
2415          child._start += amount;
2416          child._end += amount;
2417        }
2418
2419        child = child._next;
2420      }
2421
2422      if (adjustLabels) {
2423        for (p in labels) {
2424          if (labels[p] >= ignoreBeforeTime) {
2425            labels[p] += amount;
2426          }
2427        }
2428      }
2429
2430      return _uncache(this);
2431    };
2432
2433    _proto2.invalidate = function invalidate(soft) {
2434      var child = this._first;
2435      this._lock = 0;
2436
2437      while (child) {
2438        child.invalidate(soft);
2439        child = child._next;
2440      }
2441
2442      return _Animation.prototype.invalidate.call(this, soft);
2443    };
2444
2445    _proto2.clear = function clear(includeLabels) {
2446      if (includeLabels === void 0) {
2447        includeLabels = true;
2448      }
2449
2450      var child = this._first,
2451          next;
2452
2453      while (child) {
2454        next = child._next;
2455        this.remove(child);
2456        child = next;
2457      }
2458
2459      this._dp && (this._time = this._tTime = this._pTime = 0);
2460      includeLabels && (this.labels = {});
2461      return _uncache(this);
2462    };
2463
2464    _proto2.totalDuration = function totalDuration(value) {
2465      var max = 0,
2466          self = this,
2467          child = self._last,
2468          prevStart = _bigNum,
2469          prev,
2470          start,
2471          parent;
2472
2473      if (arguments.length) {
2474        return self.timeScale((self._repeat < 0 ? self.duration() : self.totalDuration()) / (self.reversed() ? -value : value));
2475      }
2476
2477      if (self._dirty) {
2478        parent = self.parent;
2479
2480        while (child) {
2481          prev = child._prev;
2482          child._dirty && child.totalDuration();
2483          start = child._start;
2484
2485          if (start > prevStart && self._sort && child._ts && !self._lock) {
2486            self._lock = 1;
2487            _addToTimeline(self, child, start - child._delay, 1)._lock = 0;
2488          } else {
2489            prevStart = start;
2490          }
2491
2492          if (start < 0 && child._ts) {
2493            max -= start;
2494
2495            if (!parent && !self._dp || parent && parent.smoothChildTiming) {
2496              self._start += start / self._ts;
2497              self._time -= start;
2498              self._tTime -= start;
2499            }
2500
2501            self.shiftChildren(-start, false, -1e999);
2502            prevStart = 0;
2503          }
2504
2505          child._end > max && child._ts && (max = child._end);
2506          child = prev;
2507        }
2508
2509        _setDuration(self, self === _globalTimeline && self._time > max ? self._time : max, 1, 1);
2510
2511        self._dirty = 0;
2512      }
2513
2514      return self._tDur;
2515    };
2516
2517    Timeline.updateRoot = function updateRoot(time) {
2518      if (_globalTimeline._ts) {
2519        _lazySafeRender(_globalTimeline, _parentToChildTotalTime(time, _globalTimeline));
2520
2521        _lastRenderedFrame = _ticker.frame;
2522      }
2523
2524      if (_ticker.frame >= _nextGCFrame) {
2525        _nextGCFrame += _config.autoSleep || 120;
2526        var child = _globalTimeline._first;
2527        if (!child || !child._ts) if (_config.autoSleep && _ticker._listeners.length < 2) {
2528          while (child && !child._ts) {
2529            child = child._next;
2530          }
2531
2532          child || _ticker.sleep();
2533        }
2534      }
2535    };
2536
2537    return Timeline;
2538  }(Animation);
2539
2540  _setDefaults(Timeline.prototype, {
2541    _lock: 0,
2542    _hasPause: 0,
2543    _forcing: 0
2544  });
2545
2546  var _addComplexStringPropTween = function _addComplexStringPropTween(target, prop, start, end, setter, stringFilter, funcParam) {
2547    var pt = new PropTween(this._pt, target, prop, 0, 1, _renderComplexString, null, setter),
2548        index = 0,
2549        matchIndex = 0,
2550        result,
2551        startNums,
2552        color,
2553        endNum,
2554        chunk,
2555        startNum,
2556        hasRandom,
2557        a;
2558    pt.b = start;
2559    pt.e = end;
2560    start += "";
2561    end += "";
2562
2563    if (hasRandom = ~end.indexOf("random(")) {
2564      end = _replaceRandom(end);
2565    }
2566
2567    if (stringFilter) {
2568      a = [start, end];
2569      stringFilter(a, target, prop);
2570      start = a[0];
2571      end = a[1];
2572    }
2573
2574    startNums = start.match(_complexStringNumExp) || [];
2575
2576    while (result = _complexStringNumExp.exec(end)) {
2577      endNum = result[0];
2578      chunk = end.substring(index, result.index);
2579
2580      if (color) {
2581        color = (color + 1) % 5;
2582      } else if (chunk.substr(-5) === "rgba(") {
2583        color = 1;
2584      }
2585
2586      if (endNum !== startNums[matchIndex++]) {
2587        startNum = parseFloat(startNums[matchIndex - 1]) || 0;
2588        pt._pt = {
2589          _next: pt._pt,
2590          p: chunk || matchIndex === 1 ? chunk : ",",
2591          s: startNum,
2592          c: endNum.charAt(1) === "=" ? _parseRelative(startNum, endNum) - startNum : parseFloat(endNum) - startNum,
2593          m: color && color < 4 ? Math.round : 0
2594        };
2595        index = _complexStringNumExp.lastIndex;
2596      }
2597    }
2598
2599    pt.c = index < end.length ? end.substring(index, end.length) : "";
2600    pt.fp = funcParam;
2601
2602    if (_relExp.test(end) || hasRandom) {
2603      pt.e = 0;
2604    }
2605
2606    this._pt = pt;
2607    return pt;
2608  },
2609      _addPropTween = function _addPropTween(target, prop, start, end, index, targets, modifier, stringFilter, funcParam, optional) {
2610    _isFunction(end) && (end = end(index || 0, target, targets));
2611    var currentValue = target[prop],
2612        parsedStart = start !== "get" ? start : !_isFunction(currentValue) ? currentValue : funcParam ? target[prop.indexOf("set") || !_isFunction(target["get" + prop.substr(3)]) ? prop : "get" + prop.substr(3)](funcParam) : target[prop](),
2613        setter = !_isFunction(currentValue) ? _setterPlain : funcParam ? _setterFuncWithParam : _setterFunc,
2614        pt;
2615
2616    if (_isString(end)) {
2617      if (~end.indexOf("random(")) {
2618        end = _replaceRandom(end);
2619      }
2620
2621      if (end.charAt(1) === "=") {
2622        pt = _parseRelative(parsedStart, end) + (getUnit(parsedStart) || 0);
2623
2624        if (pt || pt === 0) {
2625          end = pt;
2626        }
2627      }
2628    }
2629
2630    if (!optional || parsedStart !== end || _forceAllPropTweens) {
2631      if (!isNaN(parsedStart * end) && end !== "") {
2632        pt = new PropTween(this._pt, target, prop, +parsedStart || 0, end - (parsedStart || 0), typeof currentValue === "boolean" ? _renderBoolean : _renderPlain, 0, setter);
2633        funcParam && (pt.fp = funcParam);
2634        modifier && pt.modifier(modifier, this, target);
2635        return this._pt = pt;
2636      }
2637
2638      !currentValue && !(prop in target) && _missingPlugin(prop, end);
2639      return _addComplexStringPropTween.call(this, target, prop, parsedStart, end, setter, stringFilter || _config.stringFilter, funcParam);
2640    }
2641  },
2642      _processVars = function _processVars(vars, index, target, targets, tween) {
2643    _isFunction(vars) && (vars = _parseFuncOrString(vars, tween, index, target, targets));
2644
2645    if (!_isObject(vars) || vars.style && vars.nodeType || _isArray(vars) || _isTypedArray(vars)) {
2646      return _isString(vars) ? _parseFuncOrString(vars, tween, index, target, targets) : vars;
2647    }
2648
2649    var copy = {},
2650        p;
2651
2652    for (p in vars) {
2653      copy[p] = _parseFuncOrString(vars[p], tween, index, target, targets);
2654    }
2655
2656    return copy;
2657  },
2658      _checkPlugin = function _checkPlugin(property, vars, tween, index, target, targets) {
2659    var plugin, pt, ptLookup, i;
2660
2661    if (_plugins[property] && (plugin = new _plugins[property]()).init(target, plugin.rawVars ? vars[property] : _processVars(vars[property], index, target, targets, tween), tween, index, targets) !== false) {
2662      tween._pt = pt = new PropTween(tween._pt, target, property, 0, 1, plugin.render, plugin, 0, plugin.priority);
2663
2664      if (tween !== _quickTween) {
2665        ptLookup = tween._ptLookup[tween._targets.indexOf(target)];
2666        i = plugin._props.length;
2667
2668        while (i--) {
2669          ptLookup[plugin._props[i]] = pt;
2670        }
2671      }
2672    }
2673
2674    return plugin;
2675  },
2676      _overwritingTween,
2677      _forceAllPropTweens,
2678      _initTween = function _initTween(tween, time, tTime) {
2679    var vars = tween.vars,
2680        ease = vars.ease,
2681        startAt = vars.startAt,
2682        immediateRender = vars.immediateRender,
2683        lazy = vars.lazy,
2684        onUpdate = vars.onUpdate,
2685        runBackwards = vars.runBackwards,
2686        yoyoEase = vars.yoyoEase,
2687        keyframes = vars.keyframes,
2688        autoRevert = vars.autoRevert,
2689        dur = tween._dur,
2690        prevStartAt = tween._startAt,
2691        targets = tween._targets,
2692        parent = tween.parent,
2693        fullTargets = parent && parent.data === "nested" ? parent.vars.targets : targets,
2694        autoOverwrite = tween._overwrite === "auto" && !_suppressOverwrites,
2695        tl = tween.timeline,
2696        cleanVars,
2697        i,
2698        p,
2699        pt,
2700        target,
2701        hasPriority,
2702        gsData,
2703        harness,
2704        plugin,
2705        ptLookup,
2706        index,
2707        harnessVars,
2708        overwritten;
2709    tl && (!keyframes || !ease) && (ease = "none");
2710    tween._ease = _parseEase(ease, _defaults.ease);
2711    tween._yEase = yoyoEase ? _invertEase(_parseEase(yoyoEase === true ? ease : yoyoEase, _defaults.ease)) : 0;
2712
2713    if (yoyoEase && tween._yoyo && !tween._repeat) {
2714      yoyoEase = tween._yEase;
2715      tween._yEase = tween._ease;
2716      tween._ease = yoyoEase;
2717    }
2718
2719    tween._from = !tl && !!vars.runBackwards;
2720
2721    if (!tl || keyframes && !vars.stagger) {
2722      harness = targets[0] ? _getCache(targets[0]).harness : 0;
2723      harnessVars = harness && vars[harness.prop];
2724      cleanVars = _copyExcluding(vars, _reservedProps);
2725
2726      if (prevStartAt) {
2727        prevStartAt._zTime < 0 && prevStartAt.progress(1);
2728        time < 0 && runBackwards && immediateRender && !autoRevert ? prevStartAt.render(-1, true) : prevStartAt.revert(runBackwards && dur ? _revertConfigNoKill : _startAtRevertConfig);
2729        prevStartAt._lazy = 0;
2730      }
2731
2732      if (startAt) {
2733        _removeFromParent(tween._startAt = Tween.set(targets, _setDefaults({
2734          data: "isStart",
2735          overwrite: false,
2736          parent: parent,
2737          immediateRender: true,
2738          lazy: !prevStartAt && _isNotFalse(lazy),
2739          startAt: null,
2740          delay: 0,
2741          onUpdate: onUpdate && function () {
2742            return _callback(tween, "onUpdate");
2743          },
2744          stagger: 0
2745        }, startAt)));
2746
2747        tween._startAt._dp = 0;
2748        tween._startAt._sat = tween;
2749        time < 0 && (_reverting || !immediateRender && !autoRevert) && tween._startAt.revert(_revertConfigNoKill);
2750
2751        if (immediateRender) {
2752          if (dur && time <= 0 && tTime <= 0) {
2753            time && (tween._zTime = time);
2754            return;
2755          }
2756        }
2757      } else if (runBackwards && dur) {
2758        if (!prevStartAt) {
2759          time && (immediateRender = false);
2760          p = _setDefaults({
2761            overwrite: false,
2762            data: "isFromStart",
2763            lazy: immediateRender && !prevStartAt && _isNotFalse(lazy),
2764            immediateRender: immediateRender,
2765            stagger: 0,
2766            parent: parent
2767          }, cleanVars);
2768          harnessVars && (p[harness.prop] = harnessVars);
2769
2770          _removeFromParent(tween._startAt = Tween.set(targets, p));
2771
2772          tween._startAt._dp = 0;
2773          tween._startAt._sat = tween;
2774          time < 0 && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween._startAt.render(-1, true));
2775          tween._zTime = time;
2776
2777          if (!immediateRender) {
2778            _initTween(tween._startAt, _tinyNum, _tinyNum);
2779          } else if (!time) {
2780            return;
2781          }
2782        }
2783      }
2784
2785      tween._pt = tween._ptCache = 0;
2786      lazy = dur && _isNotFalse(lazy) || lazy && !dur;
2787
2788      for (i = 0; i < targets.length; i++) {
2789        target = targets[i];
2790        gsData = target._gsap || _harness(targets)[i]._gsap;
2791        tween._ptLookup[i] = ptLookup = {};
2792        _lazyLookup[gsData.id] && _lazyTweens.length && _lazyRender();
2793        index = fullTargets === targets ? i : fullTargets.indexOf(target);
2794
2795        if (harness && (plugin = new harness()).init(target, harnessVars || cleanVars, tween, index, fullTargets) !== false) {
2796          tween._pt = pt = new PropTween(tween._pt, target, plugin.name, 0, 1, plugin.render, plugin, 0, plugin.priority);
2797
2798          plugin._props.forEach(function (name) {
2799            ptLookup[name] = pt;
2800          });
2801
2802          plugin.priority && (hasPriority = 1);
2803        }
2804
2805        if (!harness || harnessVars) {
2806          for (p in cleanVars) {
2807            if (_plugins[p] && (plugin = _checkPlugin(p, cleanVars, tween, index, target, fullTargets))) {
2808              plugin.priority && (hasPriority = 1);
2809            } else {
2810              ptLookup[p] = pt = _addPropTween.call(tween, target, p, "get", cleanVars[p], index, fullTargets, 0, vars.stringFilter);
2811            }
2812          }
2813        }
2814
2815        tween._op && tween._op[i] && tween.kill(target, tween._op[i]);
2816
2817        if (autoOverwrite && tween._pt) {
2818          _overwritingTween = tween;
2819
2820          _globalTimeline.killTweensOf(target, ptLookup, tween.globalTime(time));
2821
2822          overwritten = !tween.parent;
2823          _overwritingTween = 0;
2824        }
2825
2826        tween._pt && lazy && (_lazyLookup[gsData.id] = 1);
2827      }
2828
2829      hasPriority && _sortPropTweensByPriority(tween);
2830      tween._onInit && tween._onInit(tween);
2831    }
2832
2833    tween._onUpdate = onUpdate;
2834    tween._initted = (!tween._op || tween._pt) && !overwritten;
2835    keyframes && time <= 0 && tl.render(_bigNum, true, true);
2836  },
2837      _updatePropTweens = function _updatePropTweens(tween, property, value, start, startIsRelative, ratio, time, skipRecursion) {
2838    var ptCache = (tween._pt && tween._ptCache || (tween._ptCache = {}))[property],
2839        pt,
2840        rootPT,
2841        lookup,
2842        i;
2843
2844    if (!ptCache) {
2845      ptCache = tween._ptCache[property] = [];
2846      lookup = tween._ptLookup;
2847      i = tween._targets.length;
2848
2849      while (i--) {
2850        pt = lookup[i][property];
2851
2852        if (pt && pt.d && pt.d._pt) {
2853          pt = pt.d._pt;
2854
2855          while (pt && pt.p !== property && pt.fp !== property) {
2856            pt = pt._next;
2857          }
2858        }
2859
2860        if (!pt) {
2861          _forceAllPropTweens = 1;
2862          tween.vars[property] = "+=0";
2863
2864          _initTween(tween, time);
2865
2866          _forceAllPropTweens = 0;
2867          return skipRecursion ? _warn(property + " not eligible for reset") : 1;
2868        }
2869
2870        ptCache.push(pt);
2871      }
2872    }
2873
2874    i = ptCache.length;
2875
2876    while (i--) {
2877      rootPT = ptCache[i];
2878      pt = rootPT._pt || rootPT;
2879      pt.s = (start || start === 0) && !startIsRelative ? start : pt.s + (start || 0) + ratio * pt.c;
2880      pt.c = value - pt.s;
2881      rootPT.e && (rootPT.e = _round(value) + getUnit(rootPT.e));
2882      rootPT.b && (rootPT.b = pt.s + getUnit(rootPT.b));
2883    }
2884  },
2885      _addAliasesToVars = function _addAliasesToVars(targets, vars) {
2886    var harness = targets[0] ? _getCache(targets[0]).harness : 0,
2887        propertyAliases = harness && harness.aliases,
2888        copy,
2889        p,
2890        i,
2891        aliases;
2892
2893    if (!propertyAliases) {
2894      return vars;
2895    }
2896
2897    copy = _merge({}, vars);
2898
2899    for (p in propertyAliases) {
2900      if (p in copy) {
2901        aliases = propertyAliases[p].split(",");
2902        i = aliases.length;
2903
2904        while (i--) {
2905          copy[aliases[i]] = copy[p];
2906        }
2907      }
2908    }
2909
2910    return copy;
2911  },
2912      _parseKeyframe = function _parseKeyframe(prop, obj, allProps, easeEach) {
2913    var ease = obj.ease || easeEach || "power1.inOut",
2914        p,
2915        a;
2916
2917    if (_isArray(obj)) {
2918      a = allProps[prop] || (allProps[prop] = []);
2919      obj.forEach(function (value, i) {
2920        return a.push({
2921          t: i / (obj.length - 1) * 100,
2922          v: value,
2923          e: ease
2924        });
2925      });
2926    } else {
2927      for (p in obj) {
2928        a = allProps[p] || (allProps[p] = []);
2929        p === "ease" || a.push({
2930          t: parseFloat(prop),
2931          v: obj[p],
2932          e: ease
2933        });
2934      }
2935    }
2936  },
2937      _parseFuncOrString = function _parseFuncOrString(value, tween, i, target, targets) {
2938    return _isFunction(value) ? value.call(tween, i, target, targets) : _isString(value) && ~value.indexOf("random(") ? _replaceRandom(value) : value;
2939  },
2940      _staggerTweenProps = _callbackNames + "repeat,repeatDelay,yoyo,repeatRefresh,yoyoEase,autoRevert",
2941      _staggerPropsToSkip = {};
2942
2943  _forEachName(_staggerTweenProps + ",id,stagger,delay,duration,paused,scrollTrigger", function (name) {
2944    return _staggerPropsToSkip[name] = 1;
2945  });
2946
2947  var Tween = function (_Animation2) {
2948    _inheritsLoose(Tween, _Animation2);
2949
2950    function Tween(targets, vars, position, skipInherit) {
2951      var _this3;
2952
2953      if (typeof vars === "number") {
2954        position.duration = vars;
2955        vars = position;
2956        position = null;
2957      }
2958
2959      _this3 = _Animation2.call(this, skipInherit ? vars : _inheritDefaults(vars)) || this;
2960      var _this3$vars = _this3.vars,
2961          duration = _this3$vars.duration,
2962          delay = _this3$vars.delay,
2963          immediateRender = _this3$vars.immediateRender,
2964          stagger = _this3$vars.stagger,
2965          overwrite = _this3$vars.overwrite,
2966          keyframes = _this3$vars.keyframes,
2967          defaults = _this3$vars.defaults,
2968          scrollTrigger = _this3$vars.scrollTrigger,
2969          yoyoEase = _this3$vars.yoyoEase,
2970          parent = vars.parent || _globalTimeline,
2971          parsedTargets = (_isArray(targets) || _isTypedArray(targets) ? _isNumber(targets[0]) : "length" in vars) ? [targets] : toArray(targets),
2972          tl,
2973          i,
2974          copy,
2975          l,
2976          p,
2977          curTarget,
2978          staggerFunc,
2979          staggerVarsToMerge;
2980      _this3._targets = parsedTargets.length ? _harness(parsedTargets) : _warn("GSAP target " + targets + " not found. https://gsap.com", !_config.nullTargetWarn) || [];
2981      _this3._ptLookup = [];
2982      _this3._overwrite = overwrite;
2983
2984      if (keyframes || stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) {
2985        vars = _this3.vars;
2986        tl = _this3.timeline = new Timeline({
2987          data: "nested",
2988          defaults: defaults || {},
2989          targets: parent && parent.data === "nested" ? parent.vars.targets : parsedTargets
2990        });
2991        tl.kill();
2992        tl.parent = tl._dp = _assertThisInitialized(_this3);
2993        tl._start = 0;
2994
2995        if (stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) {
2996          l = parsedTargets.length;
2997          staggerFunc = stagger && distribute(stagger);
2998
2999          if (_isObject(stagger)) {
3000            for (p in stagger) {
3001              if (~_staggerTweenProps.indexOf(p)) {
3002                staggerVarsToMerge || (staggerVarsToMerge = {});
3003                staggerVarsToMerge[p] = stagger[p];
3004              }
3005            }
3006          }
3007
3008          for (i = 0; i < l; i++) {
3009            copy = _copyExcluding(vars, _staggerPropsToSkip);
3010            copy.stagger = 0;
3011            yoyoEase && (copy.yoyoEase = yoyoEase);
3012            staggerVarsToMerge && _merge(copy, staggerVarsToMerge);
3013            curTarget = parsedTargets[i];
3014            copy.duration = +_parseFuncOrString(duration, _assertThisInitialized(_this3), i, curTarget, parsedTargets);
3015            copy.delay = (+_parseFuncOrString(delay, _assertThisInitialized(_this3), i, curTarget, parsedTargets) || 0) - _this3._delay;
3016
3017            if (!stagger && l === 1 && copy.delay) {
3018              _this3._delay = delay = copy.delay;
3019              _this3._start += delay;
3020              copy.delay = 0;
3021            }
3022
3023            tl.to(curTarget, copy, staggerFunc ? staggerFunc(i, curTarget, parsedTargets) : 0);
3024            tl._ease = _easeMap.none;
3025          }
3026
3027          tl.duration() ? duration = delay = 0 : _this3.timeline = 0;
3028        } else if (keyframes) {
3029          _inheritDefaults(_setDefaults(tl.vars.defaults, {
3030            ease: "none"
3031          }));
3032
3033          tl._ease = _parseEase(keyframes.ease || vars.ease || "none");
3034          var time = 0,
3035              a,
3036              kf,
3037              v;
3038
3039          if (_isArray(keyframes)) {
vendor: 6,477 bytes, lines 3040-3246
3040            keyframes.forEach(function (frame) {
3041              return tl.to(parsedTargets, frame, ">");
3042            });
3043            tl.duration();
3044          } else {
3045            copy = {};
3046
3047            for (p in keyframes) {
3048              p === "ease" || p === "easeEach" || _parseKeyframe(p, keyframes[p], copy, keyframes.easeEach);
3049            }
3050
3051            for (p in copy) {
3052              a = copy[p].sort(function (a, b) {
3053                return a.t - b.t;
3054              });
3055              time = 0;
3056
3057              for (i = 0; i < a.length; i++) {
3058                kf = a[i];
3059                v = {
3060                  ease: kf.e,
3061                  duration: (kf.t - (i ? a[i - 1].t : 0)) / 100 * duration
3062                };
3063                v[p] = kf.v;
3064                tl.to(parsedTargets, v, time);
3065                time += v.duration;
3066              }
3067            }
3068
3069            tl.duration() < duration && tl.to({}, {
3070              duration: duration - tl.duration()
3071            });
3072          }
3073        }
3074
3075        duration || _this3.duration(duration = tl.duration());
3076      } else {
3077        _this3.timeline = 0;
3078      }
3079
3080      if (overwrite === true && !_suppressOverwrites) {
3081        _overwritingTween = _assertThisInitialized(_this3);
3082
3083        _globalTimeline.killTweensOf(parsedTargets);
3084
3085        _overwritingTween = 0;
3086      }
3087
3088      _addToTimeline(parent, _assertThisInitialized(_this3), position);
3089
3090      vars.reversed && _this3.reverse();
3091      vars.paused && _this3.paused(true);
3092
3093      if (immediateRender || !duration && !keyframes && _this3._start === _roundPrecise(parent._time) && _isNotFalse(immediateRender) && _hasNoPausedAncestors(_assertThisInitialized(_this3)) && parent.data !== "nested") {
3094        _this3._tTime = -_tinyNum;
3095
3096        _this3.render(Math.max(0, -delay) || 0);
3097      }
3098
3099      scrollTrigger && _scrollTrigger(_assertThisInitialized(_this3), scrollTrigger);
3100      return _this3;
3101    }
3102
3103    var _proto3 = Tween.prototype;
3104
3105    _proto3.render = function render(totalTime, suppressEvents, force) {
3106      var prevTime = this._time,
3107          tDur = this._tDur,
3108          dur = this._dur,
3109          isNegative = totalTime < 0,
3110          tTime = totalTime > tDur - _tinyNum && !isNegative ? tDur : totalTime < _tinyNum ? 0 : totalTime,
3111          time,
3112          pt,
3113          iteration,
3114          cycleDuration,
3115          prevIteration,
3116          isYoyo,
3117          ratio,
3118          timeline,
3119          yoyoEase;
3120
3121      if (!dur) {
3122        _renderZeroDurationTween(this, totalTime, suppressEvents, force);
3123      } else if (tTime !== this._tTime || !totalTime || force || !this._initted && this._tTime || this._startAt && this._zTime < 0 !== isNegative) {
3124        time = tTime;
3125        timeline = this.timeline;
3126
3127        if (this._repeat) {
3128          cycleDuration = dur + this._rDelay;
3129
3130          if (this._repeat < -1 && isNegative) {
3131            return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);
3132          }
3133
3134          time = _roundPrecise(tTime % cycleDuration);
3135
3136          if (tTime === tDur) {
3137            iteration = this._repeat;
3138            time = dur;
3139          } else {
3140            iteration = ~~(tTime / cycleDuration);
3141
3142            if (iteration && iteration === _roundPrecise(tTime / cycleDuration)) {
3143              time = dur;
3144              iteration--;
3145            }
3146
3147            time > dur && (time = dur);
3148          }
3149
3150          isYoyo = this._yoyo && iteration & 1;
3151
3152          if (isYoyo) {
3153            yoyoEase = this._yEase;
3154            time = dur - time;
3155          }
3156
3157          prevIteration = _animationCycle(this._tTime, cycleDuration);
3158
3159          if (time === prevTime && !force && this._initted && iteration === prevIteration) {
3160            this._tTime = tTime;
3161            return this;
3162          }
3163
3164          if (iteration !== prevIteration) {
3165            timeline && this._yEase && _propagateYoyoEase(timeline, isYoyo);
3166
3167            if (this.vars.repeatRefresh && !isYoyo && !this._lock && this._time !== cycleDuration && this._initted) {
3168              this._lock = force = 1;
3169              this.render(_roundPrecise(cycleDuration * iteration), true).invalidate()._lock = 0;
3170            }
3171          }
3172        }
3173
3174        if (!this._initted) {
3175          if (_attemptInitTween(this, isNegative ? totalTime : time, force, suppressEvents, tTime)) {
3176            this._tTime = 0;
3177            return this;
3178          }
3179
3180          if (prevTime !== this._time && !(force && this.vars.repeatRefresh && iteration !== prevIteration)) {
3181            return this;
3182          }
3183
3184          if (dur !== this._dur) {
3185            return this.render(totalTime, suppressEvents, force);
3186          }
3187        }
3188
3189        this._tTime = tTime;
3190        this._time = time;
3191
3192        if (!this._act && this._ts) {
3193          this._act = 1;
3194          this._lazy = 0;
3195        }
3196
3197        this.ratio = ratio = (yoyoEase || this._ease)(time / dur);
3198
3199        if (this._from) {
3200          this.ratio = ratio = 1 - ratio;
3201        }
3202
3203        if (time && !prevTime && !suppressEvents && !iteration) {
3204          _callback(this, "onStart");
3205
3206          if (this._tTime !== tTime) {
3207            return this;
3208          }
3209        }
3210
3211        pt = this._pt;
3212
3213        while (pt) {
3214          pt.r(ratio, pt.d);
3215          pt = pt._next;
3216        }
3217
3218        timeline && timeline.render(totalTime < 0 ? totalTime : timeline._dur * timeline._ease(time / this._dur), suppressEvents, force) || this._startAt && (this._zTime = totalTime);
3219
3220        if (this._onUpdate && !suppressEvents) {
3221          isNegative && _rewindStartAt(this, totalTime, suppressEvents, force);
3222
3223          _callback(this, "onUpdate");
3224        }
3225
3226        this._repeat && iteration !== prevIteration && this.vars.onRepeat && !suppressEvents && this.parent && _callback(this, "onRepeat");
3227
3228        if ((tTime === this._tDur || !tTime) && this._tTime === tTime) {
3229          isNegative && !this._onUpdate && _rewindStartAt(this, totalTime, true, true);
3230          (totalTime || !dur) && (tTime === this._tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1);
3231
3232          if (!suppressEvents && !(isNegative && !prevTime) && (tTime || prevTime || isYoyo)) {
3233            _callback(this, tTime === tDur ? "onComplete" : "onReverseComplete", true);
3234
3235            this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();
3236          }
3237        }
3238      }
3239
3240      return this;
3241    };
3242
3243    _proto3.targets = function targets() {
3244      return this._targets;
3245    };
3246
vendor: 1,310 bytes, lines 3247-3280
3247    _proto3.invalidate = function invalidate(soft) {
3248      (!soft || !this.vars.runBackwards) && (this._startAt = 0);
3249      this._pt = this._op = this._onUpdate = this._lazy = this.ratio = 0;
3250      this._ptLookup = [];
3251      this.timeline && this.timeline.invalidate(soft);
3252      return _Animation2.prototype.invalidate.call(this, soft);
3253    };
3254
3255    _proto3.resetTo = function resetTo(property, value, start, startIsRelative, skipRecursion) {
3256      _tickerActive || _ticker.wake();
3257      this._ts || this.play();
3258      var time = Math.min(this._dur, (this._dp._time - this._start) * this._ts),
3259          ratio;
3260      this._initted || _initTween(this, time);
3261      ratio = this._ease(time / this._dur);
3262
3263      if (_updatePropTweens(this, property, value, start, startIsRelative, ratio, time, skipRecursion)) {
3264        return this.resetTo(property, value, start, startIsRelative, 1);
3265      }
3266
3267      _alignPlayhead(this, 0);
3268
3269      this.parent || _addLinkedListItem(this._dp, this, "_first", "_last", this._dp._sort ? "_start" : 0);
3270      return this.render(0);
3271    };
3272
3273    _proto3.kill = function kill(targets, vars) {
3274      if (vars === void 0) {
3275        vars = "all";
3276      }
3277
3278      if (!targets && (!vars || vars === "all")) {
3279        this._lazy = this._pt = 0;
3280        return this.parent ? _interrupt(this) :
vendor: 16,527 bytes, lines 3280-3882
3280 this;
3281      }
3282
3283      if (this.timeline) {
3284        var tDur = this.timeline.totalDuration();
3285        this.timeline.killTweensOf(targets, vars, _overwritingTween && _overwritingTween.vars.overwrite !== true)._first || _interrupt(this);
3286        this.parent && tDur !== this.timeline.totalDuration() && _setDuration(this, this._dur * this.timeline._tDur / tDur, 0, 1);
3287        return this;
3288      }
3289
3290      var parsedTargets = this._targets,
3291          killingTargets = targets ? toArray(targets) : parsedTargets,
3292          propTweenLookup = this._ptLookup,
3293          firstPT = this._pt,
3294          overwrittenProps,
3295          curLookup,
3296          curOverwriteProps,
3297          props,
3298          p,
3299          pt,
3300          i;
3301
3302      if ((!vars || vars === "all") && _arraysMatch(parsedTargets, killingTargets)) {
3303        vars === "all" && (this._pt = 0);
3304        return _interrupt(this);
3305      }
3306
3307      overwrittenProps = this._op = this._op || [];
3308
3309      if (vars !== "all") {
3310        if (_isString(vars)) {
3311          p = {};
3312
3313          _forEachName(vars, function (name) {
3314            return p[name] = 1;
3315          });
3316
3317          vars = p;
3318        }
3319
3320        vars = _addAliasesToVars(parsedTargets, vars);
3321      }
3322
3323      i = parsedTargets.length;
3324
3325      while (i--) {
3326        if (~killingTargets.indexOf(parsedTargets[i])) {
3327          curLookup = propTweenLookup[i];
3328
3329          if (vars === "all") {
3330            overwrittenProps[i] = vars;
3331            props = curLookup;
3332            curOverwriteProps = {};
3333          } else {
3334            curOverwriteProps = overwrittenProps[i] = overwrittenProps[i] || {};
3335            props = vars;
3336          }
3337
3338          for (p in props) {
3339            pt = curLookup && curLookup[p];
3340
3341            if (pt) {
3342              if (!("kill" in pt.d) || pt.d.kill(p) === true) {
3343                _removeLinkedListItem(this, pt, "_pt");
3344              }
3345
3346              delete curLookup[p];
3347            }
3348
3349            if (curOverwriteProps !== "all") {
3350              curOverwriteProps[p] = 1;
3351            }
3352          }
3353        }
3354      }
3355
3356      this._initted && !this._pt && firstPT && _interrupt(this);
3357      return this;
3358    };
3359
3360    Tween.to = function to(targets, vars) {
3361      return new Tween(targets, vars, arguments[2]);
3362    };
3363
3364    Tween.from = function from(targets, vars) {
3365      return _createTweenType(1, arguments);
3366    };
3367
3368    Tween.delayedCall = function delayedCall(delay, callback, params, scope) {
3369      return new Tween(callback, 0, {
3370        immediateRender: false,
3371        lazy: false,
3372        overwrite: false,
3373        delay: delay,
3374        onComplete: callback,
3375        onReverseComplete: callback,
3376        onCompleteParams: params,
3377        onReverseCompleteParams: params,
3378        callbackScope: scope
3379      });
3380    };
3381
3382    Tween.fromTo = function fromTo(targets, fromVars, toVars) {
3383      return _createTweenType(2, arguments);
3384    };
3385
3386    Tween.set = function set(targets, vars) {
3387      vars.duration = 0;
3388      vars.repeatDelay || (vars.repeat = 0);
3389      return new Tween(targets, vars);
3390    };
3391
3392    Tween.killTweensOf = function killTweensOf(targets, props, onlyActive) {
3393      return _globalTimeline.killTweensOf(targets, props, onlyActive);
3394    };
3395
3396    return Tween;
3397  }(Animation);
3398
3399  _setDefaults(Tween.prototype, {
3400    _targets: [],
3401    _lazy: 0,
3402    _startAt: 0,
3403    _op: 0,
3404    _onInit: 0
3405  });
3406
3407  _forEachName("staggerTo,staggerFrom,staggerFromTo", function (name) {
3408    Tween[name] = function () {
3409      var tl = new Timeline(),
3410          params = _slice.call(arguments, 0);
3411
3412      params.splice(name === "staggerFromTo" ? 5 : 4, 0, 0);
3413      return tl[name].apply(tl, params);
3414    };
3415  });
3416
3417  var _setterPlain = function _setterPlain(target, property, value) {
3418    return target[property] = value;
3419  },
3420      _setterFunc = function _setterFunc(target, property, value) {
3421    return target[property](value);
3422  },
3423      _setterFuncWithParam = function _setterFuncWithParam(target, property, value, data) {
3424    return target[property](data.fp, value);
3425  },
3426      _setterAttribute = function _setterAttribute(target, property, value) {
3427    return target.setAttribute(property, value);
3428  },
3429      _getSetter = function _getSetter(target, property) {
3430    return _isFunction(target[property]) ? _setterFunc : _isUndefined(target[property]) && target.setAttribute ? _setterAttribute : _setterPlain;
3431  },
3432      _renderPlain = function _renderPlain(ratio, data) {
3433    return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 1000000) / 1000000, data);
3434  },
3435      _renderBoolean = function _renderBoolean(ratio, data) {
3436    return data.set(data.t, data.p, !!(data.s + data.c * ratio), data);
3437  },
3438      _renderComplexString = function _renderComplexString(ratio, data) {
3439    var pt = data._pt,
3440        s = "";
3441
3442    if (!ratio && data.b) {
3443      s = data.b;
3444    } else if (ratio === 1 && data.e) {
3445      s = data.e;
3446    } else {
3447      while (pt) {
3448        s = pt.p + (pt.m ? pt.m(pt.s + pt.c * ratio) : Math.round((pt.s + pt.c * ratio) * 10000) / 10000) + s;
3449        pt = pt._next;
3450      }
3451
3452      s += data.c;
3453    }
3454
3455    data.set(data.t, data.p, s, data);
3456  },
3457      _renderPropTweens = function _renderPropTweens(ratio, data) {
3458    var pt = data._pt;
3459
3460    while (pt) {
3461      pt.r(ratio, pt.d);
3462      pt = pt._next;
3463    }
3464  },
3465      _addPluginModifier = function _addPluginModifier(modifier, tween, target, property) {
3466    var pt = this._pt,
3467        next;
3468
3469    while (pt) {
3470      next = pt._next;
3471      pt.p === property && pt.modifier(modifier, tween, target);
3472      pt = next;
3473    }
3474  },
3475      _killPropTweensOf = function _killPropTweensOf(property) {
3476    var pt = this._pt,
3477        hasNonDependentRemaining,
3478        next;
3479
3480    while (pt) {
3481      next = pt._next;
3482
3483      if (pt.p === property && !pt.op || pt.op === property) {
3484        _removeLinkedListItem(this, pt, "_pt");
3485      } else if (!pt.dep) {
3486        hasNonDependentRemaining = 1;
3487      }
3488
3489      pt = next;
3490    }
3491
3492    return !hasNonDependentRemaining;
3493  },
3494      _setterWithModifier = function _setterWithModifier(target, property, value, data) {
3495    data.mSet(target, property, data.m.call(data.tween, value, data.mt), data);
3496  },
3497      _sortPropTweensByPriority = function _sortPropTweensByPriority(parent) {
3498    var pt = parent._pt,
3499        next,
3500        pt2,
3501        first,
3502        last;
3503
3504    while (pt) {
3505      next = pt._next;
3506      pt2 = first;
3507
3508      while (pt2 && pt2.pr > pt.pr) {
3509        pt2 = pt2._next;
3510      }
3511
3512      if (pt._prev = pt2 ? pt2._prev : last) {
3513        pt._prev._next = pt;
3514      } else {
3515        first = pt;
3516      }
3517
3518      if (pt._next = pt2) {
3519        pt2._prev = pt;
3520      } else {
3521        last = pt;
3522      }
3523
3524      pt = next;
3525    }
3526
3527    parent._pt = first;
3528  };
3529
3530  var PropTween = function () {
3531    function PropTween(next, target, prop, start, change, renderer, data, setter, priority) {
3532      this.t = target;
3533      this.s = start;
3534      this.c = change;
3535      this.p = prop;
3536      this.r = renderer || _renderPlain;
3537      this.d = data || this;
3538      this.set = setter || _setterPlain;
3539      this.pr = priority || 0;
3540      this._next = next;
3541
3542      if (next) {
3543        next._prev = this;
3544      }
3545    }
3546
3547    var _proto4 = PropTween.prototype;
3548
3549    _proto4.modifier = function modifier(func, tween, target) {
3550      this.mSet = this.mSet || this.set;
3551      this.set = _setterWithModifier;
3552      this.m = func;
3553      this.mt = target;
3554      this.tween = tween;
3555    };
3556
3557    return PropTween;
3558  }();
3559
3560  _forEachName(_callbackNames + "parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger", function (name) {
3561    return _reservedProps[name] = 1;
3562  });
3563
3564  _globals.TweenMax = _globals.TweenLite = Tween;
3565  _globals.TimelineLite = _globals.TimelineMax = Timeline;
3566  _globalTimeline = new Timeline({
3567    sortChildren: false,
3568    defaults: _defaults,
3569    autoRemoveChildren: true,
3570    id: "root",
3571    smoothChildTiming: true
3572  });
3573  _config.stringFilter = _colorStringFilter;
3574
3575  var _media = [],
3576      _listeners = {},
3577      _emptyArray = [],
3578      _lastMediaTime = 0,
3579      _contextID = 0,
3580      _dispatch = function _dispatch(type) {
3581    return (_listeners[type] || _emptyArray).map(function (f) {
3582      return f();
3583    });
3584  },
3585      _onMediaChange = function _onMediaChange() {
3586    var time = Date.now(),
3587        matches = [];
3588
3589    if (time - _lastMediaTime > 2) {
3590      _dispatch("matchMediaInit");
3591
3592      _media.forEach(function (c) {
3593        var queries = c.queries,
3594            conditions = c.conditions,
3595            match,
3596            p,
3597            anyMatch,
3598            toggled;
3599
3600        for (p in queries) {
3601          match = _win.matchMedia(queries[p]).matches;
3602          match && (anyMatch = 1);
3603
3604          if (match !== conditions[p]) {
3605            conditions[p] = match;
3606            toggled = 1;
3607          }
3608        }
3609
3610        if (toggled) {
3611          c.revert();
3612          anyMatch && matches.push(c);
3613        }
3614      });
3615
3616      _dispatch("matchMediaRevert");
3617
3618      matches.forEach(function (c) {
3619        return c.onMatch(c, function (func) {
3620          return c.add(null, func);
3621        });
3622      });
3623      _lastMediaTime = time;
3624
3625      _dispatch("matchMedia");
3626    }
3627  };
3628
3629  var Context = function () {
3630    function Context(func, scope) {
3631      this.selector = scope && selector(scope);
3632      this.data = [];
3633      this._r = [];
3634      this.isReverted = false;
3635      this.id = _contextID++;
3636      func && this.add(func);
3637    }
3638
3639    var _proto5 = Context.prototype;
3640
3641    _proto5.add = function add(name, func, scope) {
3642      if (_isFunction(name)) {
3643        scope = func;
3644        func = name;
3645        name = _isFunction;
3646      }
3647
3648      var self = this,
3649          f = function f() {
3650        var prev = _context,
3651            prevSelector = self.selector,
3652            result;
3653        prev && prev !== self && prev.data.push(self);
3654        scope && (self.selector = selector(scope));
3655        _context = self;
3656        result = func.apply(self, arguments);
3657        _isFunction(result) && self._r.push(result);
3658        _context = prev;
3659        self.selector = prevSelector;
3660        self.isReverted = false;
3661        return result;
3662      };
3663
3664      self.last = f;
3665      return name === _isFunction ? f(self, function (func) {
3666        return self.add(null, func);
3667      }) : name ? self[name] = f : f;
3668    };
3669
3670    _proto5.ignore = function ignore(func) {
3671      var prev = _context;
3672      _context = null;
3673      func(this);
3674      _context = prev;
3675    };
3676
3677    _proto5.getTweens = function getTweens() {
3678      var a = [];
3679      this.data.forEach(function (e) {
3680        return e instanceof Context ? a.push.apply(a, e.getTweens()) : e instanceof Tween && !(e.parent && e.parent.data === "nested") && a.push(e);
3681      });
3682      return a;
3683    };
3684
3685    _proto5.clear = function clear() {
3686      this._r.length = this.data.length = 0;
3687    };
3688
3689    _proto5.kill = function kill(revert, matchMedia) {
3690      var _this4 = this;
3691
3692      if (revert) {
3693        (function () {
3694          var tweens = _this4.getTweens(),
3695              i = _this4.data.length,
3696              t;
3697
3698          while (i--) {
3699            t = _this4.data[i];
3700
3701            if (t.data === "isFlip") {
3702              t.revert();
3703              t.getChildren(true, true, false).forEach(function (tween) {
3704                return tweens.splice(tweens.indexOf(tween), 1);
3705              });
3706            }
3707          }
3708
3709          tweens.map(function (t) {
3710            return {
3711              g: t._dur || t._delay || t._sat && !t._sat.vars.immediateRender ? t.globalTime(0) : -Infinity,
3712              t: t
3713            };
3714          }).sort(function (a, b) {
3715            return b.g - a.g || -Infinity;
3716          }).forEach(function (o) {
3717            return o.t.revert(revert);
3718          });
3719          i = _this4.data.length;
3720
3721          while (i--) {
3722            t = _this4.data[i];
3723
3724            if (t instanceof Timeline) {
3725              if (t.data !== "nested") {
3726                t.scrollTrigger && t.scrollTrigger.revert();
3727                t.kill();
3728              }
3729            } else {
3730              !(t instanceof Tween) && t.revert && t.revert(revert);
3731            }
3732          }
3733
3734          _this4._r.forEach(function (f) {
3735            return f(revert, _this4);
3736          });
3737
3738          _this4.isReverted = true;
3739        })();
3740      } else {
3741        this.data.forEach(function (e) {
3742          return e.kill && e.kill();
3743        });
3744      }
3745
3746      this.clear();
3747
3748      if (matchMedia) {
3749        var i = _media.length;
3750
3751        while (i--) {
3752          _media[i].id === this.id && _media.splice(i, 1);
3753        }
3754      }
3755    };
3756
3757    _proto5.revert = function revert(config) {
3758      this.kill(config || {});
3759    };
3760
3761    return Context;
3762  }();
3763
3764  var MatchMedia = function () {
3765    function MatchMedia(scope) {
3766      this.contexts = [];
3767      this.scope = scope;
3768      _context && _context.data.push(this);
3769    }
3770
3771    var _proto6 = MatchMedia.prototype;
3772
3773    _proto6.add = function add(conditions, func, scope) {
3774      _isObject(conditions) || (conditions = {
3775        matches: conditions
3776      });
3777      var context = new Context(0, scope || this.scope),
3778          cond = context.conditions = {},
3779          mq,
3780          p,
3781          active;
3782      _context && !context.selector && (context.selector = _context.selector);
3783      this.contexts.push(context);
3784      func = context.add("onMatch", func);
3785      context.queries = conditions;
3786
3787      for (p in conditions) {
3788        if (p === "all") {
3789          active = 1;
3790        } else {
3791          mq = _win.matchMedia(conditions[p]);
3792
3793          if (mq) {
3794            _media.indexOf(context) < 0 && _media.push(context);
3795            (cond[p] = mq.matches) && (active = 1);
3796            mq.addListener ? mq.addListener(_onMediaChange) : mq.addEventListener("change", _onMediaChange);
3797          }
3798        }
3799      }
3800
3801      active && func(context, function (f) {
3802        return context.add(null, f);
3803      });
3804      return this;
3805    };
3806
3807    _proto6.revert = function revert(config) {
3808      this.kill(config || {});
3809    };
3810
3811    _proto6.kill = function kill(revert) {
3812      this.contexts.forEach(function (c) {
3813        return c.kill(revert, true);
3814      });
3815    };
3816
3817    return MatchMedia;
3818  }();
3819
3820  var _gsap = {
3821    registerPlugin: function registerPlugin() {
3822      for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
3823        args[_key2] = arguments[_key2];
3824      }
3825
3826      args.forEach(function (config) {
3827        return _createPlugin(config);
3828      });
3829    },
3830    timeline: function timeline(vars) {
3831      return new Timeline(vars);
3832    },
3833    getTweensOf: function getTweensOf(targets, onlyActive) {
3834      return _globalTimeline.getTweensOf(targets, onlyActive);
3835    },
3836    getProperty: function getProperty(target, property, unit, uncache) {
3837      _isString(target) && (target = toArray(target)[0]);
3838
3839      var getter = _getCache(target || {}).get,
3840          format = unit ? _passThrough : _numericIfPossible;
3841
3842      unit === "native" && (unit = "");
3843      return !target ? target : !property ? function (property, unit, uncache) {
3844        return format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));
3845      } : format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));
3846    },
3847    quickSetter: function quickSetter(target, property, unit) {
3848      target = toArray(target);
3849
3850      if (target.length > 1) {
3851        var setters = target.map(function (t) {
3852          return gsap.quickSetter(t, property, unit);
3853        }),
3854            l = setters.length;
3855        return function (value) {
3856          var i = l;
3857
3858          while (i--) {
3859            setters[i](value);
3860          }
3861        };
3862      }
3863
3864      target = target[0] || {};
3865
3866      var Plugin = _plugins[property],
3867          cache = _getCache(target),
3868          p = cache.harness && (cache.harness.aliases || {})[property] || property,
3869          setter = Plugin ? function (value) {
3870        var p = new Plugin();
3871        _quickTween._pt = 0;
3872        p.init(target, unit ? value + unit : value, _quickTween, 0, [target]);
3873        p.render(1, p);
3874        _quickTween._pt && _renderPropTweens(1, _quickTween);
3875      } : cache.set(target, p);
3876
3877      return Plugin ? setter : function (value) {
3878        return setter(target, p, unit ? value + unit : value, cache, 1);
3879      };
3880    },
3881    quickTo: function quickTo(target, property, vars) {
3882      var _
3882merge2;
3883
3884      var tween = gsap.to(target, _merge((_merge2 = {}, _merge2[property] = "+=0.1", _merge2.paused = true, _merge
vendor: 5,649 bytes, lines 3884-4086
38842), vars || {})),
3885          func = function func(value, start, startIsRelative) {
3886        return tween.resetTo(property, value, start, startIsRelative);
3887      };
3888
3889      func.tween = tween;
3890      return func;
3891    },
3892    isTweening: function isTweening(targets) {
3893      return _globalTimeline.getTweensOf(targets, true).length > 0;
3894    },
3895    defaults: function defaults(value) {
3896      value && value.ease && (value.ease = _parseEase(value.ease, _defaults.ease));
3897      return _mergeDeep(_defaults, value || {});
3898    },
3899    config: function config(value) {
3900      return _mergeDeep(_config, value || {});
3901    },
3902    registerEffect: function registerEffect(_ref3) {
3903      var name = _ref3.name,
3904          effect = _ref3.effect,
3905          plugins = _ref3.plugins,
3906          defaults = _ref3.defaults,
3907          extendTimeline = _ref3.extendTimeline;
3908      (plugins || "").split(",").forEach(function (pluginName) {
3909        return pluginName && !_plugins[pluginName] && !_globals[pluginName] && _warn(name + " effect requires " + pluginName + " plugin.");
3910      });
3911
3912      _effects[name] = function (targets, vars, tl) {
3913        return effect(toArray(targets), _setDefaults(vars || {}, defaults), tl);
3914      };
3915
3916      if (extendTimeline) {
3917        Timeline.prototype[name] = function (targets, vars, position) {
3918          return this.add(_effects[name](targets, _isObject(vars) ? vars : (position = vars) && {}, this), position);
3919        };
3920      }
3921    },
3922    registerEase: function registerEase(name, ease) {
3923      _easeMap[name] = _parseEase(ease);
3924    },
3925    parseEase: function parseEase(ease, defaultEase) {
3926      return arguments.length ? _parseEase(ease, defaultEase) : _easeMap;
3927    },
3928    getById: function getById(id) {
3929      return _globalTimeline.getById(id);
3930    },
3931    exportRoot: function exportRoot(vars, includeDelayedCalls) {
3932      if (vars === void 0) {
3933        vars = {};
3934      }
3935
3936      var tl = new Timeline(vars),
3937          child,
3938          next;
3939      tl.smoothChildTiming = _isNotFalse(vars.smoothChildTiming);
3940
3941      _globalTimeline.remove(tl);
3942
3943      tl._dp = 0;
3944      tl._time = tl._tTime = _globalTimeline._time;
3945      child = _globalTimeline._first;
3946
3947      while (child) {
3948        next = child._next;
3949
3950        if (includeDelayedCalls || !(!child._dur && child instanceof Tween && child.vars.onComplete === child._targets[0])) {
3951          _addToTimeline(tl, child, child._start - child._delay);
3952        }
3953
3954        child = next;
3955      }
3956
3957      _addToTimeline(_globalTimeline, tl, 0);
3958
3959      return tl;
3960    },
3961    context: function context(func, scope) {
3962      return func ? new Context(func, scope) : _context;
3963    },
3964    matchMedia: function matchMedia(scope) {
3965      return new MatchMedia(scope);
3966    },
3967    matchMediaRefresh: function matchMediaRefresh() {
3968      return _media.forEach(function (c) {
3969        var cond = c.conditions,
3970            found,
3971            p;
3972
3973        for (p in cond) {
3974          if (cond[p]) {
3975            cond[p] = false;
3976            found = 1;
3977          }
3978        }
3979
3980        found && c.revert();
3981      }) || _onMediaChange();
3982    },
3983    addEventListener: function addEventListener(type, callback) {
3984      var a = _listeners[type] || (_listeners[type] = []);
3985      ~a.indexOf(callback) || a.push(callback);
3986    },
3987    removeEventListener: function removeEventListener(type, callback) {
3988      var a = _listeners[type],
3989          i = a && a.indexOf(callback);
3990      i >= 0 && a.splice(i, 1);
3991    },
3992    utils: {
3993      wrap: wrap,
3994      wrapYoyo: wrapYoyo,
3995      distribute: distribute,
3996      random: random,
3997      snap: snap,
3998      normalize: normalize,
3999      getUnit: getUnit,
4000      clamp: clamp,
4001      splitColor: splitColor,
4002      toArray: toArray,
4003      selector: selector,
4004      mapRange: mapRange,
4005      pipe: pipe,
4006      unitize: unitize,
4007      interpolate: interpolate,
4008      shuffle: shuffle
4009    },
4010    install: _install,
4011    effects: _effects,
4012    ticker: _ticker,
4013    updateRoot: Timeline.updateRoot,
4014    plugins: _plugins,
4015    globalTimeline: _globalTimeline,
4016    core: {
4017      PropTween: PropTween,
4018      globals: _addGlobal,
4019      Tween: Tween,
4020      Timeline: Timeline,
4021      Animation: Animation,
4022      getCache: _getCache,
4023      _removeLinkedListItem: _removeLinkedListItem,
4024      reverting: function reverting() {
4025        return _reverting;
4026      },
4027      context: function context(toAdd) {
4028        if (toAdd && _context) {
4029          _context.data.push(toAdd);
4030
4031          toAdd._ctx = _context;
4032        }
4033
4034        return _context;
4035      },
4036      suppressOverwrites: function suppressOverwrites(value) {
4037        return _suppressOverwrites = value;
4038      }
4039    }
4040  };
4041
4042  _forEachName("to,from,fromTo,delayedCall,set,killTweensOf", function (name) {
4043    return _gsap[name] = Tween[name];
4044  });
4045
4046  _ticker.add(Timeline.updateRoot);
4047
4048  _quickTween = _gsap.to({}, {
4049    duration: 0
4050  });
4051
4052  var _getPluginPropTween = function _getPluginPropTween(plugin, prop) {
4053    var pt = plugin._pt;
4054
4055    while (pt && pt.p !== prop && pt.op !== prop && pt.fp !== prop) {
4056      pt = pt._next;
4057    }
4058
4059    return pt;
4060  },
4061      _addModifiers = function _addModifiers(tween, modifiers) {
4062    var targets = tween._targets,
4063        p,
4064        i,
4065        pt;
4066
4067    for (p in modifiers) {
4068      i = targets.length;
4069
4070      while (i--) {
4071        pt = tween._ptLookup[i][p];
4072
4073        if (pt && (pt = pt.d)) {
4074          if (pt._pt) {
4075            pt = _getPluginPropTween(pt, p);
4076          }
4077
4078          pt && pt.modifier && pt.modifier(modifiers[p], tween, targets[i], p);
4079        }
4080      }
4081    }
4082  },
4083      _buildModifierPlugin = function _buildModifierPlugin(name, modifier) {
4084    return {
4085      name: name,
4086      
vendor: 21,125 bytes, lines 4086-4737
4086rawVars: 1,
4087      init: function init(target, vars, tween) {
4088        tween._onInit = function (tween) {
4089          var temp, p;
4090
4091          if (_isString(vars)) {
4092            temp = {};
4093
4094            _forEachName(vars, function (name) {
4095              return temp[name] = 1;
4096            });
4097
4098            vars = temp;
4099          }
4100
4101          if (modifier) {
4102            temp = {};
4103
4104            for (p in vars) {
4105              temp[p] = modifier(vars[p]);
4106            }
4107
4108            vars = temp;
4109          }
4110
4111          _addModifiers(tween, vars);
4112        };
4113      }
4114    };
4115  };
4116
4117  var gsap = _gsap.registerPlugin({
4118    name: "attr",
4119    init: function init(target, vars, tween, index, targets) {
4120      var p, pt, v;
4121      this.tween = tween;
4122
4123      for (p in vars) {
4124        v = target.getAttribute(p) || "";
4125        pt = this.add(target, "setAttribute", (v || 0) + "", vars[p], index, targets, 0, 0, p);
4126        pt.op = p;
4127        pt.b = v;
4128
4129        this._props.push(p);
4130      }
4131    },
4132    render: function render(ratio, data) {
4133      var pt = data._pt;
4134
4135      while (pt) {
4136        _reverting ? pt.set(pt.t, pt.p, pt.b, pt) : pt.r(ratio, pt.d);
4137        pt = pt._next;
4138      }
4139    }
4140  }, {
4141    name: "endArray",
4142    init: function init(target, value) {
4143      var i = value.length;
4144
4145      while (i--) {
4146        this.add(target, i, target[i] || 0, value[i], 0, 0, 0, 0, 0, 1);
4147      }
4148    }
4149  }, _buildModifierPlugin("roundProps", _roundModifier), _buildModifierPlugin("modifiers"), _buildModifierPlugin("snap", snap)) || _gsap;
4150  Tween.version = Timeline.version = gsap.version = "3.12.5";
4151  _coreReady = 1;
4152  _windowExists() && _wake();
4153  var Power0 = _easeMap.Power0,
4154      Power1 = _easeMap.Power1,
4155      Power2 = _easeMap.Power2,
4156      Power3 = _easeMap.Power3,
4157      Power4 = _easeMap.Power4,
4158      Linear = _easeMap.Linear,
4159      Quad = _easeMap.Quad,
4160      Cubic = _easeMap.Cubic,
4161      Quart = _easeMap.Quart,
4162      Quint = _easeMap.Quint,
4163      Strong = _easeMap.Strong,
4164      Elastic = _easeMap.Elastic,
4165      Back = _easeMap.Back,
4166      SteppedEase = _easeMap.SteppedEase,
4167      Bounce = _easeMap.Bounce,
4168      Sine = _easeMap.Sine,
4169      Expo = _easeMap.Expo,
4170      Circ = _easeMap.Circ;
4171
4172  var _win$1,
4173      _doc$1,
4174      _docElement,
4175      _pluginInitted,
4176      _tempDiv,
4177      _tempDivStyler,
4178      _recentSetterPlugin,
4179      _reverting$1,
4180      _windowExists$1 = function _windowExists() {
4181    return typeof window !== "undefined";
4182  },
4183      _transformProps = {},
4184      _RAD2DEG = 180 / Math.PI,
4185      _DEG2RAD = Math.PI / 180,
4186      _atan2 = Math.atan2,
4187      _bigNum$1 = 1e8,
4188      _capsExp = /([A-Z])/g,
4189      _horizontalExp = /(left|right|width|margin|padding|x)/i,
4190      _complexExp = /[\s,\(]\S/,
4191      _propertyAliases = {
4192    autoAlpha: "opacity,visibility",
4193    scale: "scaleX,scaleY",
4194    alpha: "opacity"
4195  },
4196      _renderCSSProp = function _renderCSSProp(ratio, data) {
4197    return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);
4198  },
4199      _renderPropWithEnd = function _renderPropWithEnd(ratio, data) {
4200    return data.set(data.t, data.p, ratio === 1 ? data.e : Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);
4201  },
4202      _renderCSSPropWithBeginning = function _renderCSSPropWithBeginning(ratio, data) {
4203    return data.set(data.t, data.p, ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data);
4204  },
4205      _renderRoundedCSSProp = function _renderRoundedCSSProp(ratio, data) {
4206    var value = data.s + data.c * ratio;
4207    data.set(data.t, data.p, ~~(value + (value < 0 ? -.5 : .5)) + data.u, data);
4208  },
4209      _renderNonTweeningValue = function _renderNonTweeningValue(ratio, data) {
4210    return data.set(data.t, data.p, ratio ? data.e : data.b, data);
4211  },
4212      _renderNonTweeningValueOnlyAtEnd = function _renderNonTweeningValueOnlyAtEnd(ratio, data) {
4213    return data.set(data.t, data.p, ratio !== 1 ? data.b : data.e, data);
4214  },
4215      _setterCSSStyle = function _setterCSSStyle(target, property, value) {
4216    return target.style[property] = value;
4217  },
4218      _setterCSSProp = function _setterCSSProp(target, property, value) {
4219    return target.style.setProperty(property, value);
4220  },
4221      _setterTransform = function _setterTransform(target, property, value) {
4222    return target._gsap[property] = value;
4223  },
4224      _setterScale = function _setterScale(target, property, value) {
4225    return target._gsap.scaleX = target._gsap.scaleY = value;
4226  },
4227      _setterScaleWithRender = function _setterScaleWithRender(target, property, value, data, ratio) {
4228    var cache = target._gsap;
4229    cache.scaleX = cache.scaleY = value;
4230    cache.renderTransform(ratio, cache);
4231  },
4232      _setterTransformWithRender = function _setterTransformWithRender(target, property, value, data, ratio) {
4233    var cache = target._gsap;
4234    cache[property] = value;
4235    cache.renderTransform(ratio, cache);
4236  },
4237      _transformProp = "transform",
4238      _transformOriginProp = _transformProp + "Origin",
4239      _saveStyle = function _saveStyle(property, isNotCSS) {
4240    var _this = this;
4241
4242    var target = this.target,
4243        style = target.style,
4244        cache = target._gsap;
4245
4246    if (property in _transformProps && style) {
4247      this.tfm = this.tfm || {};
4248
4249      if (property !== "transform") {
4250        property = _propertyAliases[property] || property;
4251        ~property.indexOf(",") ? property.split(",").forEach(function (a) {
4252          return _this.tfm[a] = _get(target, a);
4253        }) : this.tfm[property] = cache.x ? cache[property] : _get(target, property);
4254        property === _transformOriginProp && (this.tfm.zOrigin = cache.zOrigin);
4255      } else {
4256        return _propertyAliases.transform.split(",").forEach(function (p) {
4257          return _saveStyle.call(_this, p, isNotCSS);
4258        });
4259      }
4260
4261      if (this.props.indexOf(_transformProp) >= 0) {
4262        return;
4263      }
4264
4265      if (cache.svg) {
4266        this.svgo = target.getAttribute("data-svg-origin");
4267        this.props.push(_transformOriginProp, isNotCSS, "");
4268      }
4269
4270      property = _transformProp;
4271    }
4272
4273    (style || isNotCSS) && this.props.push(property, isNotCSS, style[property]);
4274  },
4275      _removeIndependentTransforms = function _removeIndependentTransforms(style) {
4276    if (style.translate) {
4277      style.removeProperty("translate");
4278      style.removeProperty("scale");
4279      style.removeProperty("rotate");
4280    }
4281  },
4282      _revertStyle = function _revertStyle() {
4283    var props = this.props,
4284        target = this.target,
4285        style = target.style,
4286        cache = target._gsap,
4287        i,
4288        p;
4289
4290    for (i = 0; i < props.length; i += 3) {
4291      props[i + 1] ? target[props[i]] = props[i + 2] : props[i + 2] ? style[props[i]] = props[i + 2] : style.removeProperty(props[i].substr(0, 2) === "--" ? props[i] : props[i].replace(_capsExp, "-$1").toLowerCase());
4292    }
4293
4294    if (this.tfm) {
4295      for (p in this.tfm) {
4296        cache[p] = this.tfm[p];
4297      }
4298
4299      if (cache.svg) {
4300        cache.renderTransform();
4301        target.setAttribute("data-svg-origin", this.svgo || "");
4302      }
4303
4304      i = _reverting$1();
4305
4306      if ((!i || !i.isStart) && !style[_transformProp]) {
4307        _removeIndependentTransforms(style);
4308
4309        if (cache.zOrigin && style[_transformOriginProp]) {
4310          style[_transformOriginProp] += " " + cache.zOrigin + "px";
4311          cache.zOrigin = 0;
4312          cache.renderTransform();
4313        }
4314
4315        cache.uncache = 1;
4316      }
4317    }
4318  },
4319      _getStyleSaver = function _getStyleSaver(target, properties) {
4320    var saver = {
4321      target: target,
4322      props: [],
4323      revert: _revertStyle,
4324      save: _saveStyle
4325    };
4326    target._gsap || gsap.core.getCache(target);
4327    properties && properties.split(",").forEach(function (p) {
4328      return saver.save(p);
4329    });
4330    return saver;
4331  },
4332      _supports3D,
4333      _createElement = function _createElement(type, ns) {
4334    var e = _doc$1.createElementNS ? _doc$1.createElementNS((ns || "http://www.w3.org/1999/xhtml").replace(/^https/, "http"), type) : _doc$1.createElement(type);
4335    return e && e.style ? e : _doc$1.createElement(type);
4336  },
4337      _getComputedProperty = function _getComputedProperty(target, property, skipPrefixFallback) {
4338    var cs = getComputedStyle(target);
4339    return cs[property] || cs.getPropertyValue(property.replace(_capsExp, "-$1").toLowerCase()) || cs.getPropertyValue(property) || !skipPrefixFallback && _getComputedProperty(target, _checkPropPrefix(property) || property, 1) || "";
4340  },
4341      _prefixes = "O,Moz,ms,Ms,Webkit".split(","),
4342      _checkPropPrefix = function _checkPropPrefix(property, element, preferPrefix) {
4343    var e = element || _tempDiv,
4344        s = e.style,
4345        i = 5;
4346
4347    if (property in s && !preferPrefix) {
4348      return property;
4349    }
4350
4351    property = property.charAt(0).toUpperCase() + property.substr(1);
4352
4353    while (i-- && !(_prefixes[i] + property in s)) {}
4354
4355    return i < 0 ? null : (i === 3 ? "ms" : i >= 0 ? _prefixes[i] : "") + property;
4356  },
4357      _initCore = function _initCore() {
4358    if (_windowExists$1() && window.document) {
4359      _win$1 = window;
4360      _doc$1 = _win$1.document;
4361      _docElement = _doc$1.documentElement;
4362      _tempDiv = _createElement("div") || {
4363        style: {}
4364      };
4365      _tempDivStyler = _createElement("div");
4366      _transformProp = _checkPropPrefix(_transformProp);
4367      _transformOriginProp = _transformProp + "Origin";
4368      _tempDiv.style.cssText = "border-width:0;line-height:0;position:absolute;padding:0";
4369      _supports3D = !!_checkPropPrefix("perspective");
4370      _reverting$1 = gsap.core.reverting;
4371      _pluginInitted = 1;
4372    }
4373  },
4374      _getBBoxHack = function _getBBoxHack(swapIfPossible) {
4375    var svg = _createElement("svg", this.ownerSVGElement && this.ownerSVGElement.getAttribute("xmlns") || "http://www.w3.org/2000/svg"),
4376        oldParent = this.parentNode,
4377        oldSibling = this.nextSibling,
4378        oldCSS = this.style.cssText,
4379        bbox;
4380
4381    _docElement.appendChild(svg);
4382
4383    svg.appendChild(this);
4384    this.style.display = "block";
4385
4386    if (swapIfPossible) {
4387      try {
4388        bbox = this.getBBox();
4389        this._gsapBBox = this.getBBox;
4390        this.getBBox = _getBBoxHack;
4391      } catch (e) {}
4392    } else if (this._gsapBBox) {
4393      bbox = this._gsapBBox();
4394    }
4395
4396    if (oldParent) {
4397      if (oldSibling) {
4398        oldParent.insertBefore(this, oldSibling);
4399      } else {
4400        oldParent.appendChild(this);
4401      }
4402    }
4403
4404    _docElement.removeChild(svg);
4405
4406    this.style.cssText = oldCSS;
4407    return bbox;
4408  },
4409      _getAttributeFallbacks = function _getAttributeFallbacks(target, attributesArray) {
4410    var i = attributesArray.length;
4411
4412    while (i--) {
4413      if (target.hasAttribute(attributesArray[i])) {
4414        return target.getAttribute(attributesArray[i]);
4415      }
4416    }
4417  },
4418      _getBBox = function _getBBox(target) {
4419    var bounds;
4420
4421    try {
4422      bounds = target.getBBox();
4423    } catch (error) {
4424      bounds = _getBBoxHack.call(target, true);
4425    }
4426
4427    bounds && (bounds.width || bounds.height) || target.getBBox === _getBBoxHack || (bounds = _getBBoxHack.call(target, true));
4428    return bounds && !bounds.width && !bounds.x && !bounds.y ? {
4429      x: +_getAttributeFallbacks(target, ["x", "cx", "x1"]) || 0,
4430      y: +_getAttributeFallbacks(target, ["y", "cy", "y1"]) || 0,
4431      width: 0,
4432      height: 0
4433    } : bounds;
4434  },
4435      _isSVG = function _isSVG(e) {
4436    return !!(e.getCTM && (!e.parentNode || e.ownerSVGElement) && _getBBox(e));
4437  },
4438      _removeProperty = function _removeProperty(target, property) {
4439    if (property) {
4440      var style = target.style,
4441          first2Chars;
4442
4443      if (property in _transformProps && property !== _transformOriginProp) {
4444        property = _transformProp;
4445      }
4446
4447      if (style.removeProperty) {
4448        first2Chars = property.substr(0, 2);
4449
4450        if (first2Chars === "ms" || property.substr(0, 6) === "webkit") {
4451          property = "-" + property;
4452        }
4453
4454        style.removeProperty(first2Chars === "--" ? property : property.replace(_capsExp, "-$1").toLowerCase());
4455      } else {
4456        style.removeAttribute(property);
4457      }
4458    }
4459  },
4460      _addNonTweeningPT = function _addNonTweeningPT(plugin, target, property, beginning, end, onlySetAtEnd) {
4461    var pt = new PropTween(plugin._pt, target, property, 0, 1, onlySetAtEnd ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue);
4462    plugin._pt = pt;
4463    pt.b = beginning;
4464    pt.e = end;
4465
4466    plugin._props.push(property);
4467
4468    return pt;
4469  },
4470      _nonConvertibleUnits = {
4471    deg: 1,
4472    rad: 1,
4473    turn: 1
4474  },
4475      _nonStandardLayouts = {
4476    grid: 1,
4477    flex: 1
4478  },
4479      _convertToUnit = function _convertToUnit(target, property, value, unit) {
4480    var curValue = parseFloat(value) || 0,
4481        curUnit = (value + "").trim().substr((curValue + "").length) || "px",
4482        style = _tempDiv.style,
4483        horizontal = _horizontalExp.test(property),
4484        isRootSVG = target.tagName.toLowerCase() === "svg",
4485        measureProperty = (isRootSVG ? "client" : "offset") + (horizontal ? "Width" : "Height"),
4486        amount = 100,
4487        toPixels = unit === "px",
4488        toPercent = unit === "%",
4489        px,
4490        parent,
4491        cache,
4492        isSVG;
4493
4494    if (unit === curUnit || !curValue || _nonConvertibleUnits[unit] || _nonConvertibleUnits[curUnit]) {
4495      return curValue;
4496    }
4497
4498    curUnit !== "px" && !toPixels && (curValue = _convertToUnit(target, property, value, "px"));
4499    isSVG = target.getCTM && _isSVG(target);
4500
4501    if ((toPercent || curUnit === "%") && (_transformProps[property] || ~property.indexOf("adius"))) {
4502      px = isSVG ? target.getBBox()[horizontal ? "width" : "height"] : target[measureProperty];
4503      return _round(toPercent ? curValue / px * amount : curValue / 100 * px);
4504    }
4505
4506    style[horizontal ? "width" : "height"] = amount + (toPixels ? curUnit : unit);
4507    parent = ~property.indexOf("adius") || unit === "em" && target.appendChild && !isRootSVG ? target : target.parentNode;
4508
4509    if (isSVG) {
4510      parent = (target.ownerSVGElement || {}).parentNode;
4511    }
4512
4513    if (!parent || parent === _doc$1 || !parent.appendChild) {
4514      parent = _doc$1.body;
4515    }
4516
4517    cache = parent._gsap;
4518
4519    if (cache && toPercent && cache.width && horizontal && cache.time === _ticker.time && !cache.uncache) {
4520      return _round(curValue / cache.width * amount);
4521    } else {
4522      if (toPercent && (property === "height" || property === "width")) {
4523        var v = target.style[property];
4524        target.style[property] = amount + unit;
4525        px = target[measureProperty];
4526        v ? target.style[property] = v : _removeProperty(target, property);
4527      } else {
4528        (toPercent || curUnit === "%") && !_nonStandardLayouts[_getComputedProperty(parent, "display")] && (style.position = _getComputedProperty(target, "position"));
4529        parent === target && (style.position = "static");
4530        parent.appendChild(_tempDiv);
4531        px = _tempDiv[measureProperty];
4532        parent.removeChild(_tempDiv);
4533        style.position = "absolute";
4534      }
4535
4536      if (horizontal && toPercent) {
4537        cache = _getCache(parent);
4538        cache.time = _ticker.time;
4539        cache.width = parent[measureProperty];
4540      }
4541    }
4542
4543    return _round(toPixels ? px * curValue / amount : px && curValue ? amount / px * curValue : 0);
4544  },
4545      _get = function _get(target, property, unit, uncache) {
4546    var value;
4547    _pluginInitted || _initCore();
4548
4549    if (property in _propertyAliases && property !== "transform") {
4550      property = _propertyAliases[property];
4551
4552      if (~property.indexOf(",")) {
4553        property = property.split(",")[0];
4554      }
4555    }
4556
4557    if (_transformProps[property] && property !== "transform") {
4558      value = _parseTransform(target, uncache);
4559      value = property !== "transformOrigin" ? value[property] : value.svg ? value.origin : _firstTwoOnly(_getComputedProperty(target, _transformOriginProp)) + " " + value.zOrigin + "px";
4560    } else {
4561      value = target.style[property];
4562
4563      if (!value || value === "auto" || uncache || ~(value + "").indexOf("calc(")) {
4564        value = _specialProps[property] && _specialProps[property](target, property, unit) || _getComputedProperty(target, property) || _getProperty(target, property) || (property === "opacity" ? 1 : 0);
4565      }
4566    }
4567
4568    return unit && !~(value + "").trim().indexOf(" ") ? _convertToUnit(target, property, value, unit) + unit : value;
4569  },
4570      _tweenComplexCSSString = function _tweenComplexCSSString(target, prop, start, end) {
4571    if (!start || start === "none") {
4572      var p = _checkPropPrefix(prop, target, 1),
4573          s = p && _getComputedProperty(target, p, 1);
4574
4575      if (s && s !== start) {
4576        prop = p;
4577        start = s;
4578      } else if (prop === "borderColor") {
4579        start = _getComputedProperty(target, "borderTopColor");
4580      }
4581    }
4582
4583    var pt = new PropTween(this._pt, target.style, prop, 0, 1, _renderComplexString),
4584        index = 0,
4585        matchIndex = 0,
4586        a,
4587        result,
4588        startValues,
4589        startNum,
4590        color,
4591        startValue,
4592        endValue,
4593        endNum,
4594        chunk,
4595        endUnit,
4596        startUnit,
4597        endValues;
4598    pt.b = start;
4599    pt.e = end;
4600    start += "";
4601    end += "";
4602
4603    if (end === "auto") {
4604      startValue = target.style[prop];
4605      target.style[prop] = end;
4606      end = _getComputedProperty(target, prop) || end;
4607      startValue ? target.style[prop] = startValue : _removeProperty(target, prop);
4608    }
4609
4610    a = [start, end];
4611
4612    _colorStringFilter(a);
4613
4614    start = a[0];
4615    end = a[1];
4616    startValues = start.match(_numWithUnitExp) || [];
4617    endValues = end.match(_numWithUnitExp) || [];
4618
4619    if (endValues.length) {
4620      while (result = _numWithUnitExp.exec(end)) {
4621        endValue = result[0];
4622        chunk = end.substring(index, result.index);
4623
4624        if (color) {
4625          color = (color + 1) % 5;
4626        } else if (chunk.substr(-5) === "rgba(" || chunk.substr(-5) === "hsla(") {
4627          color = 1;
4628        }
4629
4630        if (endValue !== (startValue = startValues[matchIndex++] || "")) {
4631          startNum = parseFloat(startValue) || 0;
4632          startUnit = startValue.substr((startNum + "").length);
4633          endValue.charAt(1) === "=" && (endValue = _parseRelative(startNum, endValue) + startUnit);
4634          endNum = parseFloat(endValue);
4635          endUnit = endValue.substr((endNum + "").length);
4636          index = _numWithUnitExp.lastIndex - endUnit.length;
4637
4638          if (!endUnit) {
4639            endUnit = endUnit || _config.units[prop] || startUnit;
4640
4641            if (index === end.length) {
4642              end += endUnit;
4643              pt.e += endUnit;
4644            }
4645          }
4646
4647          if (startUnit !== endUnit) {
4648            startNum = _convertToUnit(target, prop, startValue, endUnit) || 0;
4649          }
4650
4651          pt._pt = {
4652            _next: pt._pt,
4653            p: chunk || matchIndex === 1 ? chunk : ",",
4654            s: startNum,
4655            c: endNum - startNum,
4656            m: color && color < 4 || prop === "zIndex" ? Math.round : 0
4657          };
4658        }
4659      }
4660
4661      pt.c = index < end.length ? end.substring(index, end.length) : "";
4662    } else {
4663      pt.r = prop === "display" && end === "none" ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue;
4664    }
4665
4666    _relExp.test(end) && (pt.e = 0);
4667    this._pt = pt;
4668    return pt;
4669  },
4670      _keywordToPercent = {
4671    top: "0%",
4672    bottom: "100%",
4673    left: "0%",
4674    right: "100%",
4675    center: "50%"
4676  },
4677      _convertKeywordsToPercentages = function _convertKeywordsToPercentages(value) {
4678    var split = value.split(" "),
4679        x = split[0],
4680        y = split[1] || "50%";
4681
4682    if (x === "top" || x === "bottom" || y === "left" || y === "right") {
4683      value = x;
4684      x = y;
4685      y = value;
4686    }
4687
4688    split[0] = _keywordToPercent[x] || x;
4689    split[1] = _keywordToPercent[y] || y;
4690    return split.join(" ");
4691  },
4692      _renderClearProps = function _renderClearProps(ratio, data) {
4693    if (data.tween && data.tween._time === data.tween._dur) {
4694      var target = data.t,
4695          style = target.style,
4696          props = data.u,
4697          cache = target._gsap,
4698          prop,
4699          clearTransforms,
4700          i;
4701
4702      if (props === "all" || props === true) {
4703        style.cssText = "";
4704        clearTransforms = 1;
4705      } else {
4706        props = props.split(",");
4707        i = props.length;
4708
4709        while (--i > -1) {
4710          prop = props[i];
4711
4712          if (_transformProps[prop]) {
4713            clearTransforms = 1;
4714            prop = prop === "transformOrigin" ? _transformOriginProp : _transformProp;
4715          }
4716
4717          _removeProperty(target, prop);
4718        }
4719      }
4720
4721      if (clearTransforms) {
4722        _removeProperty(target, _transformProp);
4723
4724        if (cache) {
4725          cache.svg && target.removeAttribute("transform");
4726
4727          _parseTransform(target, 1);
4728
4729          cache.uncache = 1;
4730
4731          _removeIndependentTransforms(style);
4732        }
4733      }
4734    }
4735  },
4736      _specialProps = {
4737    clearProps: function clearProps(plugin, target, property, endValue, tween) {
vendor: 1,580 bytes, lines 4738-4778
4738      if (tween.data !== "isFromStart") {
4739        var pt = plugin._pt = new PropTween(plugin._pt, target, property, 0, 0, _renderClearProps);
4740        pt.u = endValue;
4741        pt.pr = -10;
4742        pt.tween = tween;
4743
4744        plugin._props.push(property);
4745
4746        return 1;
4747      }
4748    }
4749  },
4750      _identity2DMatrix = [1, 0, 0, 1, 0, 0],
4751      _rotationalProperties = {},
4752      _isNullTransform = function _isNullTransform(value) {
4753    return value === "matrix(1, 0, 0, 1, 0, 0)" || value === "none" || !value;
4754  },
4755      _getComputedTransformMatrixAsArray = function _getComputedTransformMatrixAsArray(target) {
4756    var matrixString = _getComputedProperty(target, _transformProp);
4757
4758    return _isNullTransform(matrixString) ? _identity2DMatrix : matrixString.substr(7).match(_numExp).map(_round);
4759  },
4760      _getMatrix = function _getMatrix(target, force2D) {
4761    var cache = target._gsap || _getCache(target),
4762        style = target.style,
4763        matrix = _getComputedTransformMatrixAsArray(target),
4764        parent,
4765        nextSibling,
4766        temp,
4767        addedToDOM;
4768
4769    if (cache.svg && target.getAttribute("transform")) {
4770      temp = target.transform.baseVal.consolidate().matrix;
4771      matrix = [temp.a, temp.b, temp.c, temp.d, temp.e, temp.f];
4772      return matrix.join(",") === "1,0,0,1,0,0" ? _identity2DMatrix : matrix;
4773    } else if (matrix === _identity2DMatrix && !target.offsetParent && target !== _docElement && !cache.svg) {
4774      temp = style.display;
4775      style.display = "block";
4776      parent = target.parentNode;
4777
4778      if (!parent || !target.offsetParent
vendor: 18,926 bytes, lines 4778-5375
4778) {
4779        addedToDOM = 1;
4780        nextSibling = target.nextElementSibling;
4781
4782        _docElement.appendChild(target);
4783      }
4784
4785      matrix = _getComputedTransformMatrixAsArray(target);
4786      temp ? style.display = temp : _removeProperty(target, "display");
4787
4788      if (addedToDOM) {
4789        nextSibling ? parent.insertBefore(target, nextSibling) : parent ? parent.appendChild(target) : _docElement.removeChild(target);
4790      }
4791    }
4792
4793    return force2D && matrix.length > 6 ? [matrix[0], matrix[1], matrix[4], matrix[5], matrix[12], matrix[13]] : matrix;
4794  },
4795      _applySVGOrigin = function _applySVGOrigin(target, origin, originIsAbsolute, smooth, matrixArray, pluginToAddPropTweensTo) {
4796    var cache = target._gsap,
4797        matrix = matrixArray || _getMatrix(target, true),
4798        xOriginOld = cache.xOrigin || 0,
4799        yOriginOld = cache.yOrigin || 0,
4800        xOffsetOld = cache.xOffset || 0,
4801        yOffsetOld = cache.yOffset || 0,
4802        a = matrix[0],
4803        b = matrix[1],
4804        c = matrix[2],
4805        d = matrix[3],
4806        tx = matrix[4],
4807        ty = matrix[5],
4808        originSplit = origin.split(" "),
4809        xOrigin = parseFloat(originSplit[0]) || 0,
4810        yOrigin = parseFloat(originSplit[1]) || 0,
4811        bounds,
4812        determinant,
4813        x,
4814        y;
4815
4816    if (!originIsAbsolute) {
4817      bounds = _getBBox(target);
4818      xOrigin = bounds.x + (~originSplit[0].indexOf("%") ? xOrigin / 100 * bounds.width : xOrigin);
4819      yOrigin = bounds.y + (~(originSplit[1] || originSplit[0]).indexOf("%") ? yOrigin / 100 * bounds.height : yOrigin);
4820    } else if (matrix !== _identity2DMatrix && (determinant = a * d - b * c)) {
4821      x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + (c * ty - d * tx) / determinant;
4822      y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - (a * ty - b * tx) / determinant;
4823      xOrigin = x;
4824      yOrigin = y;
4825    }
4826
4827    if (smooth || smooth !== false && cache.smooth) {
4828      tx = xOrigin - xOriginOld;
4829      ty = yOrigin - yOriginOld;
4830      cache.xOffset = xOffsetOld + (tx * a + ty * c) - tx;
4831      cache.yOffset = yOffsetOld + (tx * b + ty * d) - ty;
4832    } else {
4833      cache.xOffset = cache.yOffset = 0;
4834    }
4835
4836    cache.xOrigin = xOrigin;
4837    cache.yOrigin = yOrigin;
4838    cache.smooth = !!smooth;
4839    cache.origin = origin;
4840    cache.originIsAbsolute = !!originIsAbsolute;
4841    target.style[_transformOriginProp] = "0px 0px";
4842
4843    if (pluginToAddPropTweensTo) {
4844      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOrigin", xOriginOld, xOrigin);
4845
4846      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOrigin", yOriginOld, yOrigin);
4847
4848      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOffset", xOffsetOld, cache.xOffset);
4849
4850      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOffset", yOffsetOld, cache.yOffset);
4851    }
4852
4853    target.setAttribute("data-svg-origin", xOrigin + " " + yOrigin);
4854  },
4855      _parseTransform = function _parseTransform(target, uncache) {
4856    var cache = target._gsap || new GSCache(target);
4857
4858    if ("x" in cache && !uncache && !cache.uncache) {
4859      return cache;
4860    }
4861
4862    var style = target.style,
4863        invertedScaleX = cache.scaleX < 0,
4864        px = "px",
4865        deg = "deg",
4866        cs = getComputedStyle(target),
4867        origin = _getComputedProperty(target, _transformOriginProp) || "0",
4868        x,
4869        y,
4870        z,
4871        scaleX,
4872        scaleY,
4873        rotation,
4874        rotationX,
4875        rotationY,
4876        skewX,
4877        skewY,
4878        perspective,
4879        xOrigin,
4880        yOrigin,
4881        matrix,
4882        angle,
4883        cos,
4884        sin,
4885        a,
4886        b,
4887        c,
4888        d,
4889        a12,
4890        a22,
4891        t1,
4892        t2,
4893        t3,
4894        a13,
4895        a23,
4896        a33,
4897        a42,
4898        a43,
4899        a32;
4900    x = y = z = rotation = rotationX = rotationY = skewX = skewY = perspective = 0;
4901    scaleX = scaleY = 1;
4902    cache.svg = !!(target.getCTM && _isSVG(target));
4903
4904    if (cs.translate) {
4905      if (cs.translate !== "none" || cs.scale !== "none" || cs.rotate !== "none") {
4906        style[_transformProp] = (cs.translate !== "none" ? "translate3d(" + (cs.translate + " 0 0").split(" ").slice(0, 3).join(", ") + ") " : "") + (cs.rotate !== "none" ? "rotate(" + cs.rotate + ") " : "") + (cs.scale !== "none" ? "scale(" + cs.scale.split(" ").join(",") + ") " : "") + (cs[_transformProp] !== "none" ? cs[_transformProp] : "");
4907      }
4908
4909      style.scale = style.rotate = style.translate = "none";
4910    }
4911
4912    matrix = _getMatrix(target, cache.svg);
4913
4914    if (cache.svg) {
4915      if (cache.uncache) {
4916        t2 = target.getBBox();
4917        origin = cache.xOrigin - t2.x + "px " + (cache.yOrigin - t2.y) + "px";
4918        t1 = "";
4919      } else {
4920        t1 = !uncache && target.getAttribute("data-svg-origin");
4921      }
4922
4923      _applySVGOrigin(target, t1 || origin, !!t1 || cache.originIsAbsolute, cache.smooth !== false, matrix);
4924    }
4925
4926    xOrigin = cache.xOrigin || 0;
4927    yOrigin = cache.yOrigin || 0;
4928
4929    if (matrix !== _identity2DMatrix) {
4930      a = matrix[0];
4931      b = matrix[1];
4932      c = matrix[2];
4933      d = matrix[3];
4934      x = a12 = matrix[4];
4935      y = a22 = matrix[5];
4936
4937      if (matrix.length === 6) {
4938        scaleX = Math.sqrt(a * a + b * b);
4939        scaleY = Math.sqrt(d * d + c * c);
4940        rotation = a || b ? _atan2(b, a) * _RAD2DEG : 0;
4941        skewX = c || d ? _atan2(c, d) * _RAD2DEG + rotation : 0;
4942        skewX && (scaleY *= Math.abs(Math.cos(skewX * _DEG2RAD)));
4943
4944        if (cache.svg) {
4945          x -= xOrigin - (xOrigin * a + yOrigin * c);
4946          y -= yOrigin - (xOrigin * b + yOrigin * d);
4947        }
4948      } else {
4949        a32 = matrix[6];
4950        a42 = matrix[7];
4951        a13 = matrix[8];
4952        a23 = matrix[9];
4953        a33 = matrix[10];
4954        a43 = matrix[11];
4955        x = matrix[12];
4956        y = matrix[13];
4957        z = matrix[14];
4958        angle = _atan2(a32, a33);
4959        rotationX = angle * _RAD2DEG;
4960
4961        if (angle) {
4962          cos = Math.cos(-angle);
4963          sin = Math.sin(-angle);
4964          t1 = a12 * cos + a13 * sin;
4965          t2 = a22 * cos + a23 * sin;
4966          t3 = a32 * cos + a33 * sin;
4967          a13 = a12 * -sin + a13 * cos;
4968          a23 = a22 * -sin + a23 * cos;
4969          a33 = a32 * -sin + a33 * cos;
4970          a43 = a42 * -sin + a43 * cos;
4971          a12 = t1;
4972          a22 = t2;
4973          a32 = t3;
4974        }
4975
4976        angle = _atan2(-c, a33);
4977        rotationY = angle * _RAD2DEG;
4978
4979        if (angle) {
4980          cos = Math.cos(-angle);
4981          sin = Math.sin(-angle);
4982          t1 = a * cos - a13 * sin;
4983          t2 = b * cos - a23 * sin;
4984          t3 = c * cos - a33 * sin;
4985          a43 = d * sin + a43 * cos;
4986          a = t1;
4987          b = t2;
4988          c = t3;
4989        }
4990
4991        angle = _atan2(b, a);
4992        rotation = angle * _RAD2DEG;
4993
4994        if (angle) {
4995          cos = Math.cos(angle);
4996          sin = Math.sin(angle);
4997          t1 = a * cos + b * sin;
4998          t2 = a12 * cos + a22 * sin;
4999          b = b * cos - a * sin;
5000          a22 = a22 * cos - a12 * sin;
5001          a = t1;
5002          a12 = t2;
5003        }
5004
5005        if (rotationX && Math.abs(rotationX) + Math.abs(rotation) > 359.9) {
5006          rotationX = rotation = 0;
5007          rotationY = 180 - rotationY;
5008        }
5009
5010        scaleX = _round(Math.sqrt(a * a + b * b + c * c));
5011        scaleY = _round(Math.sqrt(a22 * a22 + a32 * a32));
5012        angle = _atan2(a12, a22);
5013        skewX = Math.abs(angle) > 0.0002 ? angle * _RAD2DEG : 0;
5014        perspective = a43 ? 1 / (a43 < 0 ? -a43 : a43) : 0;
5015      }
5016
5017      if (cache.svg) {
5018        t1 = target.getAttribute("transform");
5019        cache.forceCSS = target.setAttribute("transform", "") || !_isNullTransform(_getComputedProperty(target, _transformProp));
5020        t1 && target.setAttribute("transform", t1);
5021      }
5022    }
5023
5024    if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
5025      if (invertedScaleX) {
5026        scaleX *= -1;
5027        skewX += rotation <= 0 ? 180 : -180;
5028        rotation += rotation <= 0 ? 180 : -180;
5029      } else {
5030        scaleY *= -1;
5031        skewX += skewX <= 0 ? 180 : -180;
5032      }
5033    }
5034
5035    uncache = uncache || cache.uncache;
5036    cache.x = x - ((cache.xPercent = x && (!uncache && cache.xPercent || (Math.round(target.offsetWidth / 2) === Math.round(-x) ? -50 : 0))) ? target.offsetWidth * cache.xPercent / 100 : 0) + px;
5037    cache.y = y - ((cache.yPercent = y && (!uncache && cache.yPercent || (Math.round(target.offsetHeight / 2) === Math.round(-y) ? -50 : 0))) ? target.offsetHeight * cache.yPercent / 100 : 0) + px;
5038    cache.z = z + px;
5039    cache.scaleX = _round(scaleX);
5040    cache.scaleY = _round(scaleY);
5041    cache.rotation = _round(rotation) + deg;
5042    cache.rotationX = _round(rotationX) + deg;
5043    cache.rotationY = _round(rotationY) + deg;
5044    cache.skewX = skewX + deg;
5045    cache.skewY = skewY + deg;
5046    cache.transformPerspective = perspective + px;
5047
5048    if (cache.zOrigin = parseFloat(origin.split(" ")[2]) || !uncache && cache.zOrigin || 0) {
5049      style[_transformOriginProp] = _firstTwoOnly(origin);
5050    }
5051
5052    cache.xOffset = cache.yOffset = 0;
5053    cache.force3D = _config.force3D;
5054    cache.renderTransform = cache.svg ? _renderSVGTransforms : _supports3D ? _renderCSSTransforms : _renderNon3DTransforms;
5055    cache.uncache = 0;
5056    return cache;
5057  },
5058      _firstTwoOnly = function _firstTwoOnly(value) {
5059    return (value = value.split(" "))[0] + " " + value[1];
5060  },
5061      _addPxTranslate = function _addPxTranslate(target, start, value) {
5062    var unit = getUnit(start);
5063    return _round(parseFloat(start) + parseFloat(_convertToUnit(target, "x", value + "px", unit))) + unit;
5064  },
5065      _renderNon3DTransforms = function _renderNon3DTransforms(ratio, cache) {
5066    cache.z = "0px";
5067    cache.rotationY = cache.rotationX = "0deg";
5068    cache.force3D = 0;
5069
5070    _renderCSSTransforms(ratio, cache);
5071  },
5072      _zeroDeg = "0deg",
5073      _zeroPx = "0px",
5074      _endParenthesis = ") ",
5075      _renderCSSTransforms = function _renderCSSTransforms(ratio, cache) {
5076    var _ref = cache || this,
5077        xPercent = _ref.xPercent,
5078        yPercent = _ref.yPercent,
5079        x = _ref.x,
5080        y = _ref.y,
5081        z = _ref.z,
5082        rotation = _ref.rotation,
5083        rotationY = _ref.rotationY,
5084        rotationX = _ref.rotationX,
5085        skewX = _ref.skewX,
5086        skewY = _ref.skewY,
5087        scaleX = _ref.scaleX,
5088        scaleY = _ref.scaleY,
5089        transformPerspective = _ref.transformPerspective,
5090        force3D = _ref.force3D,
5091        target = _ref.target,
5092        zOrigin = _ref.zOrigin,
5093        transforms = "",
5094        use3D = force3D === "auto" && ratio && ratio !== 1 || force3D === true;
5095
5096    if (zOrigin && (rotationX !== _zeroDeg || rotationY !== _zeroDeg)) {
5097      var angle = parseFloat(rotationY) * _DEG2RAD,
5098          a13 = Math.sin(angle),
5099          a33 = Math.cos(angle),
5100          cos;
5101
5102      angle = parseFloat(rotationX) * _DEG2RAD;
5103      cos = Math.cos(angle);
5104      x = _addPxTranslate(target, x, a13 * cos * -zOrigin);
5105      y = _addPxTranslate(target, y, -Math.sin(angle) * -zOrigin);
5106      z = _addPxTranslate(target, z, a33 * cos * -zOrigin + zOrigin);
5107    }
5108
5109    if (transformPerspective !== _zeroPx) {
5110      transforms += "perspective(" + transformPerspective + _endParenthesis;
5111    }
5112
5113    if (xPercent || yPercent) {
5114      transforms += "translate(" + xPercent + "%, " + yPercent + "%) ";
5115    }
5116
5117    if (use3D || x !== _zeroPx || y !== _zeroPx || z !== _zeroPx) {
5118      transforms += z !== _zeroPx || use3D ? "translate3d(" + x + ", " + y + ", " + z + ") " : "translate(" + x + ", " + y + _endParenthesis;
5119    }
5120
5121    if (rotation !== _zeroDeg) {
5122      transforms += "rotate(" + rotation + _endParenthesis;
5123    }
5124
5125    if (rotationY !== _zeroDeg) {
5126      transforms += "rotateY(" + rotationY + _endParenthesis;
5127    }
5128
5129    if (rotationX !== _zeroDeg) {
5130      transforms += "rotateX(" + rotationX + _endParenthesis;
5131    }
5132
5133    if (skewX !== _zeroDeg || skewY !== _zeroDeg) {
5134      transforms += "skew(" + skewX + ", " + skewY + _endParenthesis;
5135    }
5136
5137    if (scaleX !== 1 || scaleY !== 1) {
5138      transforms += "scale(" + scaleX + ", " + scaleY + _endParenthesis;
5139    }
5140
5141    target.style[_transformProp] = transforms || "translate(0, 0)";
5142  },
5143      _renderSVGTransforms = function _renderSVGTransforms(ratio, cache) {
5144    var _ref2 = cache || this,
5145        xPercent = _ref2.xPercent,
5146        yPercent = _ref2.yPercent,
5147        x = _ref2.x,
5148        y = _ref2.y,
5149        rotation = _ref2.rotation,
5150        skewX = _ref2.skewX,
5151        skewY = _ref2.skewY,
5152        scaleX = _ref2.scaleX,
5153        scaleY = _ref2.scaleY,
5154        target = _ref2.target,
5155        xOrigin = _ref2.xOrigin,
5156        yOrigin = _ref2.yOrigin,
5157        xOffset = _ref2.xOffset,
5158        yOffset = _ref2.yOffset,
5159        forceCSS = _ref2.forceCSS,
5160        tx = parseFloat(x),
5161        ty = parseFloat(y),
5162        a11,
5163        a21,
5164        a12,
5165        a22,
5166        temp;
5167
5168    rotation = parseFloat(rotation);
5169    skewX = parseFloat(skewX);
5170    skewY = parseFloat(skewY);
5171
5172    if (skewY) {
5173      skewY = parseFloat(skewY);
5174      skewX += skewY;
5175      rotation += skewY;
5176    }
5177
5178    if (rotation || skewX) {
5179      rotation *= _DEG2RAD;
5180      skewX *= _DEG2RAD;
5181      a11 = Math.cos(rotation) * scaleX;
5182      a21 = Math.sin(rotation) * scaleX;
5183      a12 = Math.sin(rotation - skewX) * -scaleY;
5184      a22 = Math.cos(rotation - skewX) * scaleY;
5185
5186      if (skewX) {
5187        skewY *= _DEG2RAD;
5188        temp = Math.tan(skewX - skewY);
5189        temp = Math.sqrt(1 + temp * temp);
5190        a12 *= temp;
5191        a22 *= temp;
5192
5193        if (skewY) {
5194          temp = Math.tan(skewY);
5195          temp = Math.sqrt(1 + temp * temp);
5196          a11 *= temp;
5197          a21 *= temp;
5198        }
5199      }
5200
5201      a11 = _round(a11);
5202      a21 = _round(a21);
5203      a12 = _round(a12);
5204      a22 = _round(a22);
5205    } else {
5206      a11 = scaleX;
5207      a22 = scaleY;
5208      a21 = a12 = 0;
5209    }
5210
5211    if (tx && !~(x + "").indexOf("px") || ty && !~(y + "").indexOf("px")) {
5212      tx = _convertToUnit(target, "x", x, "px");
5213      ty = _convertToUnit(target, "y", y, "px");
5214    }
5215
5216    if (xOrigin || yOrigin || xOffset || yOffset) {
5217      tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset);
5218      ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset);
5219    }
5220
5221    if (xPercent || yPercent) {
5222      temp = target.getBBox();
5223      tx = _round(tx + xPercent / 100 * temp.width);
5224      ty = _round(ty + yPercent / 100 * temp.height);
5225    }
5226
5227    temp = "matrix(" + a11 + "," + a21 + "," + a12 + "," + a22 + "," + tx + "," + ty + ")";
5228    target.setAttribute("transform", temp);
5229    forceCSS && (target.style[_transformProp] = temp);
5230  },
5231      _addRotationalPropTween = function _addRotationalPropTween(plugin, target, property, startNum, endValue) {
5232    var cap = 360,
5233        isString = _isString(endValue),
5234        endNum = parseFloat(endValue) * (isString && ~endValue.indexOf("rad") ? _RAD2DEG : 1),
5235        change = endNum - startNum,
5236        finalValue = startNum + change + "deg",
5237        direction,
5238        pt;
5239
5240    if (isString) {
5241      direction = endValue.split("_")[1];
5242
5243      if (direction === "short") {
5244        change %= cap;
5245
5246        if (change !== change % (cap / 2)) {
5247          change += change < 0 ? cap : -cap;
5248        }
5249      }
5250
5251      if (direction === "cw" && change < 0) {
5252        change = (change + cap * _bigNum$1) % cap - ~~(change / cap) * cap;
5253      } else if (direction === "ccw" && change > 0) {
5254        change = (change - cap * _bigNum$1) % cap - ~~(change / cap) * cap;
5255      }
5256    }
5257
5258    plugin._pt = pt = new PropTween(plugin._pt, target, property, startNum, change, _renderPropWithEnd);
5259    pt.e = finalValue;
5260    pt.u = "deg";
5261
5262    plugin._props.push(property);
5263
5264    return pt;
5265  },
5266      _assign = function _assign(target, source) {
5267    for (var p in source) {
5268      target[p] = source[p];
5269    }
5270
5271    return target;
5272  },
5273      _addRawTransformPTs = function _addRawTransformPTs(plugin, transforms, target) {
5274    var startCache = _assign({}, target._gsap),
5275        exclude = "perspective,force3D,transformOrigin,svgOrigin",
5276        style = target.style,
5277        endCache,
5278        p,
5279        startValue,
5280        endValue,
5281        startNum,
5282        endNum,
5283        startUnit,
5284        endUnit;
5285
5286    if (startCache.svg) {
5287      startValue = target.getAttribute("transform");
5288      target.setAttribute("transform", "");
5289      style[_transformProp] = transforms;
5290      endCache = _parseTransform(target, 1);
5291
5292      _removeProperty(target, _transformProp);
5293
5294      target.setAttribute("transform", startValue);
5295    } else {
5296      startValue = getComputedStyle(target)[_transformProp];
5297      style[_transformProp] = transforms;
5298      endCache = _parseTransform(target, 1);
5299      style[_transformProp] = startValue;
5300    }
5301
5302    for (p in _transformProps) {
5303      startValue = startCache[p];
5304      endValue = endCache[p];
5305
5306      if (startValue !== endValue && exclude.indexOf(p) < 0) {
5307        startUnit = getUnit(startValue);
5308        endUnit = getUnit(endValue);
5309        startNum = startUnit !== endUnit ? _convertToUnit(target, p, startValue, endUnit) : parseFloat(startValue);
5310        endNum = parseFloat(endValue);
5311        plugin._pt = new PropTween(plugin._pt, endCache, p, startNum, endNum - startNum, _renderCSSProp);
5312        plugin._pt.u = endUnit || 0;
5313
5314        plugin._props.push(p);
5315      }
5316    }
5317
5318    _assign(endCache, startCache);
5319  };
5320
5321  _forEachName("padding,margin,Width,Radius", function (name, index) {
5322    var t = "Top",
5323        r = "Right",
5324        b = "Bottom",
5325        l = "Left",
5326        props = (index < 3 ? [t, r, b, l] : [t + l, t + r, b + r, b + l]).map(function (side) {
5327      return index < 2 ? name + side : "border" + side + name;
5328    });
5329
5330    _specialProps[index > 1 ? "border" + name : name] = function (plugin, target, property, endValue, tween) {
5331      var a, vars;
5332
5333      if (arguments.length < 4) {
5334        a = props.map(function (prop) {
5335          return _get(plugin, prop, property);
5336        });
5337        vars = a.join(" ");
5338        return vars.split(a[0]).length === 5 ? a[0] : vars;
5339      }
5340
5341      a = (endValue + "").split(" ");
5342      vars = {};
5343      props.forEach(function (prop, i) {
5344        return vars[prop] = a[i] = a[i] || a[(i - 1) / 2 | 0];
5345      });
5346      plugin.init(target, vars, tween);
5347    };
5348  });
5349
5350  var CSSPlugin = {
5351    name: "css",
5352    register: _initCore,
5353    targetTest: function targetTest(target) {
5354      return target.style && target.nodeType;
5355    },
5356    init: function init(target, vars, tween, index, targets) {
5357      var props = this._props,
5358          style = target.style,
5359          startAt = tween.vars.startAt,
5360          startValue,
5361          endValue,
5362          endNum,
5363          startNum,
5364          type,
5365          specialProp,
5366          p,
5367          startUnit,
5368          endUnit,
5369          relative,
5370          isTransformRelated,
5371          transformPropTween,
5372          cache,
5373          smooth,
5374          hasPriority,
5375          inlineProps
vendor: 8,025 bytes, lines 5375-5562
5375;
5376      _pluginInitted || _initCore();
5377      this.styles = this.styles || _getStyleSaver(target);
5378      inlineProps = this.styles.props;
5379      this.tween = tween;
5380
5381      for (p in vars) {
5382        if (p === "autoRound") {
5383          continue;
5384        }
5385
5386        endValue = vars[p];
5387
5388        if (_plugins[p] && _checkPlugin(p, vars, tween, index, target, targets)) {
5389          continue;
5390        }
5391
5392        type = typeof endValue;
5393        specialProp = _specialProps[p];
5394
5395        if (type === "function") {
5396          endValue = endValue.call(tween, index, target, targets);
5397          type = typeof endValue;
5398        }
5399
5400        if (type === "string" && ~endValue.indexOf("random(")) {
5401          endValue = _replaceRandom(endValue);
5402        }
5403
5404        if (specialProp) {
5405          specialProp(this, target, p, endValue, tween) && (hasPriority = 1);
5406        } else if (p.substr(0, 2) === "--") {
5407          startValue = (getComputedStyle(target).getPropertyValue(p) + "").trim();
5408          endValue += "";
5409          _colorExp.lastIndex = 0;
5410
5411          if (!_colorExp.test(startValue)) {
5412            startUnit = getUnit(startValue);
5413            endUnit = getUnit(endValue);
5414          }
5415
5416          endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit);
5417          this.add(style, "setProperty", startValue, endValue, index, targets, 0, 0, p);
5418          props.push(p);
5419          inlineProps.push(p, 0, style[p]);
5420        } else if (type !== "undefined") {
5421          if (startAt && p in startAt) {
5422            startValue = typeof startAt[p] === "function" ? startAt[p].call(tween, index, target, targets) : startAt[p];
5423            _isString(startValue) && ~startValue.indexOf("random(") && (startValue = _replaceRandom(startValue));
5424            getUnit(startValue + "") || startValue === "auto" || (startValue += _config.units[p] || getUnit(_get(target, p)) || "");
5425            (startValue + "").charAt(1) === "=" && (startValue = _get(target, p));
5426          } else {
5427            startValue = _get(target, p);
5428          }
5429
5430          startNum = parseFloat(startValue);
5431          relative = type === "string" && endValue.charAt(1) === "=" && endValue.substr(0, 2);
5432          relative && (endValue = endValue.substr(2));
5433          endNum = parseFloat(endValue);
5434
5435          if (p in _propertyAliases) {
5436            if (p === "autoAlpha") {
5437              if (startNum === 1 && _get(target, "visibility") === "hidden" && endNum) {
5438                startNum = 0;
5439              }
5440
5441              inlineProps.push("visibility", 0, style.visibility);
5442
5443              _addNonTweeningPT(this, style, "visibility", startNum ? "inherit" : "hidden", endNum ? "inherit" : "hidden", !endNum);
5444            }
5445
5446            if (p !== "scale" && p !== "transform") {
5447              p = _propertyAliases[p];
5448              ~p.indexOf(",") && (p = p.split(",")[0]);
5449            }
5450          }
5451
5452          isTransformRelated = p in _transformProps;
5453
5454          if (isTransformRelated) {
5455            this.styles.save(p);
5456
5457            if (!transformPropTween) {
5458              cache = target._gsap;
5459              cache.renderTransform && !vars.parseTransform || _parseTransform(target, vars.parseTransform);
5460              smooth = vars.smoothOrigin !== false && cache.smooth;
5461              transformPropTween = this._pt = new PropTween(this._pt, style, _transformProp, 0, 1, cache.renderTransform, cache, 0, -1);
5462              transformPropTween.dep = 1;
5463            }
5464
5465            if (p === "scale") {
5466              this._pt = new PropTween(this._pt, cache, "scaleY", cache.scaleY, (relative ? _parseRelative(cache.scaleY, relative + endNum) : endNum) - cache.scaleY || 0, _renderCSSProp);
5467              this._pt.u = 0;
5468              props.push("scaleY", p);
5469              p += "X";
5470            } else if (p === "transformOrigin") {
5471              inlineProps.push(_transformOriginProp, 0, style[_transformOriginProp]);
5472              endValue = _convertKeywordsToPercentages(endValue);
5473
5474              if (cache.svg) {
5475                _applySVGOrigin(target, endValue, 0, smooth, 0, this);
5476              } else {
5477                endUnit = parseFloat(endValue.split(" ")[2]) || 0;
5478                endUnit !== cache.zOrigin && _addNonTweeningPT(this, cache, "zOrigin", cache.zOrigin, endUnit);
5479
5480                _addNonTweeningPT(this, style, p, _firstTwoOnly(startValue), _firstTwoOnly(endValue));
5481              }
5482
5483              continue;
5484            } else if (p === "svgOrigin") {
5485              _applySVGOrigin(target, endValue, 1, smooth, 0, this);
5486
5487              continue;
5488            } else if (p in _rotationalProperties) {
5489              _addRotationalPropTween(this, cache, p, startNum, relative ? _parseRelative(startNum, relative + endValue) : endValue);
5490
5491              continue;
5492            } else if (p === "smoothOrigin") {
5493              _addNonTweeningPT(this, cache, "smooth", cache.smooth, endValue);
5494
5495              continue;
5496            } else if (p === "force3D") {
5497              cache[p] = endValue;
5498              continue;
5499            } else if (p === "transform") {
5500              _addRawTransformPTs(this, endValue, target);
5501
5502              continue;
5503            }
5504          } else if (!(p in style)) {
5505            p = _checkPropPrefix(p) || p;
5506          }
5507
5508          if (isTransformRelated || (endNum || endNum === 0) && (startNum || startNum === 0) && !_complexExp.test(endValue) && p in style) {
5509            startUnit = (startValue + "").substr((startNum + "").length);
5510            endNum || (endNum = 0);
5511            endUnit = getUnit(endValue) || (p in _config.units ? _config.units[p] : startUnit);
5512            startUnit !== endUnit && (startNum = _convertToUnit(target, p, startValue, endUnit));
5513            this._pt = new PropTween(this._pt, isTransformRelated ? cache : style, p, startNum, (relative ? _parseRelative(startNum, relative + endNum) : endNum) - startNum, !isTransformRelated && (endUnit === "px" || p === "zIndex") && vars.autoRound !== false ? _renderRoundedCSSProp : _renderCSSProp);
5514            this._pt.u = endUnit || 0;
5515
5516            if (startUnit !== endUnit && endUnit !== "%") {
5517              this._pt.b = startValue;
5518              this._pt.r = _renderCSSPropWithBeginning;
5519            }
5520          } else if (!(p in style)) {
5521            if (p in target) {
5522              this.add(target, p, startValue || target[p], relative ? relative + endValue : endValue, index, targets);
5523            } else if (p !== "parseTransform") {
5524              _missingPlugin(p, endValue);
5525
5526              continue;
5527            }
5528          } else {
5529            _tweenComplexCSSString.call(this, target, p, startValue, relative ? relative + endValue : endValue);
5530          }
5531
5532          isTransformRelated || (p in style ? inlineProps.push(p, 0, style[p]) : inlineProps.push(p, 1, startValue || target[p]));
5533          props.push(p);
5534        }
5535      }
5536
5537      hasPriority && _sortPropTweensByPriority(this);
5538    },
5539    render: function render(ratio, data) {
5540      if (data.tween._time || !_reverting$1()) {
5541        var pt = data._pt;
5542
5543        while (pt) {
5544          pt.r(ratio, pt.d);
5545          pt = pt._next;
5546        }
5547      } else {
5548        data.styles.revert();
5549      }
5550    },
5551    get: _get,
5552    aliases: _propertyAliases,
5553    getSetter: function getSetter(target, property, plugin) {
5554      var p = _propertyAliases[property];
5555      p && p.indexOf(",") < 0 && (property = p);
5556      return property in _transformProps && property !== _transformOriginProp && (target._gsap.x || _get(target, "x")) ? plugin && _recentSetterPlugin === plugin ? property === "scale" ? _setterScale : _setterTransform : (_recentSetterPlugin = plugin || {}) && (property === "scale" ? _setterScaleWithRender : _setterTransformWithRender) : target.style && !_isUndefined(target.style[property]) ? _setterCSSStyle : ~property.indexOf("-") ? _setterCSSProp : _getSetter(target, property);
5557    },
5558    core: {
5559      _removeProperty: _removeProperty,
5560      _getMatrix: _getMatrix
5561    }
5562  };
vendor: 2,056 bytes, lines 5563-5621
5563  gsap.utils.checkPrefix = _checkPropPrefix;
5564  gsap.core.getStyleSaver = _getStyleSaver;
5565
5566  (function (positionAndScale, rotation, others, aliases) {
5567    var all = _forEachName(positionAndScale + "," + rotation + "," + others, function (name) {
5568      _transformProps[name] = 1;
5569    });
5570
5571    _forEachName(rotation, function (name) {
5572      _config.units[name] = "deg";
5573      _rotationalProperties[name] = 1;
5574    });
5575
5576    _propertyAliases[all[13]] = positionAndScale + "," + rotation;
5577
5578    _forEachName(aliases, function (name) {
5579      var split = name.split(":");
5580      _propertyAliases[split[1]] = all[split[0]];
5581    });
5582  })("x,y,z,scale,scaleX,scaleY,xPercent,yPercent", "rotation,rotationX,rotationY,skewX,skewY", "transform,transformOrigin,svgOrigin,force3D,smoothOrigin,transformPerspective", "0:translateX,1:translateY,2:translateZ,8:rotate,8:rotationZ,8:rotateZ,9:rotateX,10:rotateY");
5583
5584  _forEachName("x,y,z,top,right,bottom,left,width,height,fontSize,padding,margin,perspective", function (name) {
5585    _config.units[name] = "px";
5586  });
5587
5588  gsap.registerPlugin(CSSPlugin);
5589
5590  var gsapWithCSS = gsap.registerPlugin(CSSPlugin) || gsap,
5591      TweenMaxWithCSS = gsapWithCSS.core.Tween;
5592
5593  exports.Back = Back;
5594  exports.Bounce = Bounce;
5595  exports.CSSPlugin = CSSPlugin;
5596  exports.Circ = Circ;
5597  exports.Cubic = Cubic;
5598  exports.Elastic = Elastic;
5599  exports.Expo = Expo;
5600  exports.Linear = Linear;
5601  exports.Power0 = Power0;
5602  exports.Power1 = Power1;
5603  exports.Power2 = Power2;
5604  exports.Power3 = Power3;
5605  exports.Power4 = Power4;
5606  exports.Quad = Quad;
5607  exports.Quart = Quart;
5608  exports.Quint = Quint;
5609  exports.Sine = Sine;
5610  exports.SteppedEase = SteppedEase;
5611  exports.Strong = Strong;
5612  exports.TimelineLite = Timeline;
5613  exports.TimelineMax = Timeline;
5614  exports.TweenLite = Tween;
5615  exports.TweenMax = TweenMaxWithCSS;
5616  exports.default = gsapWithCSS;
5617  exports.gsap = gsapWithCSS;
5618
5619  if (typeof(window) === 'undefined' || window !== exports) {Object.defineProperty(exports, '__esModule', { value: true });} else {delete window.default;}
5620
5621})));
vendor: 247,641 bytes, lines 5622-13099
5622/*!
5623 * matter-js 0.20.0 by @liabru
5624 * http://brm.io/matter-js/
5625 * License MIT
5626 * 
5627 * The MIT License (MIT)
5628 * 
5629 * Copyright (c) Liam Brummitt and contributors.
5630 * 
5631 * Permission is hereby granted, free of charge, to any person obtaining a copy
5632 * of this software and associated documentation files (the "Software"), to deal
5633 * in the Software without restriction, including without limitation the rights
5634 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5635 * copies of the Software, and to permit persons to whom the Software is
5636 * furnished to do so, subject to the following conditions:
5637 * 
5638 * The above copyright notice and this permission notice shall be included in
5639 * all copies or substantial portions of the Software.
5640 * 
5641 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5642 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5643 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5644 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5645 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5646 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5647 * THE SOFTWARE.
5648 */
5649(function webpackUniversalModuleDefinition(root, factory) {
5650	if(typeof exports === 'object' && typeof module === 'object')
5651		module.exports = factory();
5652	else if(typeof define === 'function' && define.amd)
5653		define("Matter", [], factory);
5654	else if(typeof exports === 'object')
5655		exports["Matter"] = factory();
5656	else
5657		root["Matter"] = factory();
5658})(this, function() {
5659return /******/ (function(modules) { // webpackBootstrap
5660/******/ 	// The module cache
5661/******/ 	var installedModules = {};
5662/******/
5663/******/ 	// The require function
5664/******/ 	function __webpack_require__(moduleId) {
5665/******/
5666/******/ 		// Check if module is in cache
5667/******/ 		if(installedModules[moduleId]) {
5668/******/ 			return installedModules[moduleId].exports;
5669/******/ 		}
5670/******/ 		// Create a new module (and put it into the cache)
5671/******/ 		var module = installedModules[moduleId] = {
5672/******/ 			i: moduleId,
5673/******/ 			l: false,
5674/******/ 			exports: {}
5675/******/ 		};
5676/******/
5677/******/ 		// Execute the module function
5678/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
5679/******/
5680/******/ 		// Flag the module as loaded
5681/******/ 		module.l = true;
5682/******/
5683/******/ 		// Return the exports of the module
5684/******/ 		return module.exports;
5685/******/ 	}
5686/******/
5687/******/
5688/******/ 	// expose the modules object (__webpack_modules__)
5689/******/ 	__webpack_require__.m = modules;
5690/******/
5691/******/ 	// expose the module cache
5692/******/ 	__webpack_require__.c = installedModules;
5693/******/
5694/******/ 	// define getter function for harmony exports
5695/******/ 	__webpack_require__.d = function(exports, name, getter) {
5696/******/ 		if(!__webpack_require__.o(exports, name)) {
5697/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
5698/******/ 		}
5699/******/ 	};
5700/******/
5701/******/ 	// define __esModule on exports
5702/******/ 	__webpack_require__.r = function(exports) {
5703/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
5704/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5705/******/ 		}
5706/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
5707/******/ 	};
5708/******/
5709/******/ 	// create a fake namespace object
5710/******/ 	// mode & 1: value is a module id, require it
5711/******/ 	// mode & 2: merge all properties of value into the ns
5712/******/ 	// mode & 4: return value when already ns object
5713/******/ 	// mode & 8|1: behave like require
5714/******/ 	__webpack_require__.t = function(value, mode) {
5715/******/ 		if(mode & 1) value = __webpack_require__(value);
5716/******/ 		if(mode & 8) return value;
5717/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
5718/******/ 		var ns = Object.create(null);
5719/******/ 		__webpack_require__.r(ns);
5720/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
5721/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
5722/******/ 		return ns;
5723/******/ 	};
5724/******/
5725/******/ 	// getDefaultExport function for compatibility with non-harmony modules
5726/******/ 	__webpack_require__.n = function(module) {
5727/******/ 		var getter = module && module.__esModule ?
5728/******/ 			function getDefault() { return module['default']; } :
5729/******/ 			function getModuleExports() { return module; };
5730/******/ 		__webpack_require__.d(getter, 'a', getter);
5731/******/ 		return getter;
5732/******/ 	};
5733/******/
5734/******/ 	// Object.prototype.hasOwnProperty.call
5735/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
5736/******/
5737/******/ 	// __webpack_public_path__
5738/******/ 	__webpack_require__.p = "";
5739/******/
5740/******/
5741/******/ 	// Load entry module and return exports
5742/******/ 	return __webpack_require__(__webpack_require__.s = 20);
5743/******/ })
5744/************************************************************************/
5745/******/ ([
5746/* 0 */
5747/***/ (function(module, exports) {
5748
5749/**
5750* The `Matter.Common` module contains utility functions that are common to all modules.
5751*
5752* @class Common
5753*/
5754
5755var Common = {};
5756
5757module.exports = Common;
5758
5759(function() {
5760
5761    Common._baseDelta = 1000 / 60;
5762    Common._nextId = 0;
5763    Common._seed = 0;
5764    Common._nowStartTime = +(new Date());
5765    Common._warnedOnce = {};
5766    Common._decomp = null;
5767    
5768    /**
5769     * Extends the object in the first argument using the object in the second argument.
5770     * @method extend
5771     * @param {} obj
5772     * @param {boolean} deep
5773     * @return {} obj extended
5774     */
5775    Common.extend = function(obj, deep) {
5776        var argsStart,
5777            args,
5778            deepClone;
5779
5780        if (typeof deep === 'boolean') {
5781            argsStart = 2;
5782            deepClone = deep;
5783        } else {
5784            argsStart = 1;
5785            deepClone = true;
5786        }
5787
5788        for (var i = argsStart; i < arguments.length; i++) {
5789            var source = arguments[i];
5790
5791            if (source) {
5792                for (var prop in source) {
5793                    if (deepClone && source[prop] && source[prop].constructor === Object) {
5794                        if (!obj[prop] || obj[prop].constructor === Object) {
5795                            obj[prop] = obj[prop] || {};
5796                            Common.extend(obj[prop], deepClone, source[prop]);
5797                        } else {
5798                            obj[prop] = source[prop];
5799                        }
5800                    } else {
5801                        obj[prop] = source[prop];
5802                    }
5803                }
5804            }
5805        }
5806        
5807        return obj;
5808    };
5809
5810    /**
5811     * Creates a new clone of the object, if deep is true references will also be cloned.
5812     * @method clone
5813     * @param {} obj
5814     * @param {bool} deep
5815     * @return {} obj cloned
5816     */
5817    Common.clone = function(obj, deep) {
5818        return Common.extend({}, deep, obj);
5819    };
5820
5821    /**
5822     * Returns the list of keys for the given object.
5823     * @method keys
5824     * @param {} obj
5825     * @return {string[]} keys
5826     */
5827    Common.keys = function(obj) {
5828        if (Object.keys)
5829            return Object.keys(obj);
5830
5831        // avoid hasOwnProperty for performance
5832        var keys = [];
5833        for (var key in obj)
5834            keys.push(key);
5835        return keys;
5836    };
5837
5838    /**
5839     * Returns the list of values for the given object.
5840     * @method values
5841     * @param {} obj
5842     * @return {array} Array of the objects property values
5843     */
5844    Common.values = function(obj) {
5845        var values = [];
5846        
5847        if (Object.keys) {
5848            var keys = Object.keys(obj);
5849            for (var i = 0; i < keys.length; i++) {
5850                values.push(obj[keys[i]]);
5851            }
5852            return values;
5853        }
5854        
5855        // avoid hasOwnProperty for performance
5856        for (var key in obj)
5857            values.push(obj[key]);
5858        return values;
5859    };
5860
5861    /**
5862     * Gets a value from `base` relative to the `path` string.
5863     * @method get
5864     * @param {} obj The base object
5865     * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'
5866     * @param {number} [begin] Path slice begin
5867     * @param {number} [end] Path slice end
5868     * @return {} The object at the given path
5869     */
5870    Common.get = function(obj, path, begin, end) {
5871        path = path.split('.').slice(begin, end);
5872
5873        for (var i = 0; i < path.length; i += 1) {
5874            obj = obj[path[i]];
5875        }
5876
5877        return obj;
5878    };
5879
5880    /**
5881     * Sets a value on `base` relative to the given `path` string.
5882     * @method set
5883     * @param {} obj The base object
5884     * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'
5885     * @param {} val The value to set
5886     * @param {number} [begin] Path slice begin
5887     * @param {number} [end] Path slice end
5888     * @return {} Pass through `val` for chaining
5889     */
5890    Common.set = function(obj, path, val, begin, end) {
5891        var parts = path.split('.').slice(begin, end);
5892        Common.get(obj, path, 0, -1)[parts[parts.length - 1]] = val;
5893        return val;
5894    };
5895
5896    /**
5897     * Shuffles the given array in-place.
5898     * The function uses a seeded random generator.
5899     * @method shuffle
5900     * @param {array} array
5901     * @return {array} array shuffled randomly
5902     */
5903    Common.shuffle = function(array) {
5904        for (var i = array.length - 1; i > 0; i--) {
5905            var j = Math.floor(Common.random() * (i + 1));
5906            var temp = array[i];
5907            array[i] = array[j];
5908            array[j] = temp;
5909        }
5910        return array;
5911    };
5912
5913    /**
5914     * Randomly chooses a value from a list with equal probability.
5915     * The function uses a seeded random generator.
5916     * @method choose
5917     * @param {array} choices
5918     * @return {object} A random choice object from the array
5919     */
5920    Common.choose = function(choices) {
5921        return choices[Math.floor(Common.random() * choices.length)];
5922    };
5923
5924    /**
5925     * Returns true if the object is a HTMLElement, otherwise false.
5926     * @method isElement
5927     * @param {object} obj
5928     * @return {boolean} True if the object is a HTMLElement, otherwise false
5929     */
5930    Common.isElement = function(obj) {
5931        if (typeof HTMLElement !== 'undefined') {
5932            return obj instanceof HTMLElement;
5933        }
5934
5935        return !!(obj && obj.nodeType && obj.nodeName);
5936    };
5937
5938    /**
5939     * Returns true if the object is an array.
5940     * @method isArray
5941     * @param {object} obj
5942     * @return {boolean} True if the object is an array, otherwise false
5943     */
5944    Common.isArray = function(obj) {
5945        return Object.prototype.toString.call(obj) === '[object Array]';
5946    };
5947
5948    /**
5949     * Returns true if the object is a function.
5950     * @method isFunction
5951     * @param {object} obj
5952     * @return {boolean} True if the object is a function, otherwise false
5953     */
5954    Common.isFunction = function(obj) {
5955        return typeof obj === "function";
5956    };
5957
5958    /**
5959     * Returns true if the object is a plain object.
5960     * @method isPlainObject
5961     * @param {object} obj
5962     * @return {boolean} True if the object is a plain object, otherwise false
5963     */
5964    Common.isPlainObject = function(obj) {
5965        return typeof obj === 'object' && obj.constructor === Object;
5966    };
5967
5968    /**
5969     * Returns true if the object is a string.
5970     * @method isString
5971     * @param {object} obj
5972     * @return {boolean} True if the object is a string, otherwise false
5973     */
5974    Common.isString = function(obj) {
5975        return toString.call(obj) === '[object String]';
5976    };
5977    
5978    /**
5979     * Returns the given value clamped between a minimum and maximum value.
5980     * @method clamp
5981     * @param {number} value
5982     * @param {number} min
5983     * @param {number} max
5984     * @return {number} The value clamped between min and max inclusive
5985     */
5986    Common.clamp = function(value, min, max) {
5987        if (value < min)
5988            return min;
5989        if (value > max)
5990            return max;
5991        return value;
5992    };
5993    
5994    /**
5995     * Returns the sign of the given value.
5996     * @method sign
5997     * @param {number} value
5998     * @return {number} -1 if negative, +1 if 0 or positive
5999     */
6000    Common.sign = function(value) {
6001        return value < 0 ? -1 : 1;
6002    };
6003    
6004    /**
6005     * Returns the current timestamp since the time origin (e.g. from page load).
6006     * The result is in milliseconds and will use high-resolution timing if available.
6007     * @method now
6008     * @return {number} the current timestamp in milliseconds
6009     */
6010    Common.now = function() {
6011        if (typeof window !== 'undefined' && window.performance) {
6012            if (window.performance.now) {
6013                return window.performance.now();
6014            } else if (window.performance.webkitNow) {
6015                return window.performance.webkitNow();
6016            }
6017        }
6018
6019        if (Date.now) {
6020            return Date.now();
6021        }
6022
6023        return (new Date()) - Common._nowStartTime;
6024    };
6025    
6026    /**
6027     * Returns a random value between a minimum and a maximum value inclusive.
6028     * The function uses a seeded random generator.
6029     * @method random
6030     * @param {number} min
6031     * @param {number} max
6032     * @return {number} A random number between min and max inclusive
6033     */
6034    Common.random = function(min, max) {
6035        min = (typeof min !== "undefined") ? min : 0;
6036        max = (typeof max !== "undefined") ? max : 1;
6037        return min + _seededRandom() * (max - min);
6038    };
6039
6040    var _seededRandom = function() {
6041        // https://en.wikipedia.org/wiki/Linear_congruential_generator
6042        Common._seed = (Common._seed * 9301 + 49297) % 233280;
6043        return Common._seed / 233280;
6044    };
6045
6046    /**
6047     * Converts a CSS hex colour string into an integer.
6048     * @method colorToNumber
6049     * @param {string} colorString
6050     * @return {number} An integer representing the CSS hex string
6051     */
6052    Common.colorToNumber = function(colorString) {
6053        colorString = colorString.replace('#','');
6054
6055        if (colorString.length == 3) {
6056            colorString = colorString.charAt(0) + colorString.charAt(0)
6057                        + colorString.charAt(1) + colorString.charAt(1)
6058                        + colorString.charAt(2) + colorString.charAt(2);
6059        }
6060
6061        return parseInt(colorString, 16);
6062    };
6063
6064    /**
6065     * The console logging level to use, where each level includes all levels above and excludes the levels below.
6066     * The default level is 'debug' which shows all console messages.  
6067     *
6068     * Possible level values are:
6069     * - 0 = None
6070     * - 1 = Debug
6071     * - 2 = Info
6072     * - 3 = Warn
6073     * - 4 = Error
6074     * @static
6075     * @property logLevel
6076     * @type {Number}
6077     * @default 1
6078     */
6079    Common.logLevel = 1;
6080
6081    /**
6082     * Shows a `console.log` message only if the current `Common.logLevel` allows it.
6083     * The message will be prefixed with 'matter-js' to make it easily identifiable.
6084     * @method log
6085     * @param ...objs {} The objects to log.
6086     */
6087    Common.log = function() {
6088        if (console && Common.logLevel > 0 && Common.logLevel <= 3) {
6089            console.log.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
6090        }
6091    };
6092
6093    /**
6094     * Shows a `console.info` message only if the current `Common.logLevel` allows it.
6095     * The message will be prefixed with 'matter-js' to make it easily identifiable.
6096     * @method info
6097     * @param ...objs {} The objects to log.
6098     */
6099    Common.info = function() {
6100        if (console && Common.logLevel > 0 && Common.logLevel <= 2) {
6101            console.info.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
6102        }
6103    };
6104
6105    /**
6106     * Shows a `console.warn` message only if the current `Common.logLevel` allows it.
6107     * The message will be prefixed with 'matter-js' to make it easily identifiable.
6108     * @method warn
6109     * @param ...objs {} The objects to log.
6110     */
6111    Common.warn = function() {
6112        if (console && Common.logLevel > 0 && Common.logLevel <= 3) {
6113            console.warn.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));
6114        }
6115    };
6116
6117    /**
6118     * Uses `Common.warn` to log the given message one time only.
6119     * @method warnOnce
6120     * @param ...objs {} The objects to log.
6121     */
6122    Common.warnOnce = function() {
6123        var message = Array.prototype.slice.call(arguments).join(' ');
6124
6125        if (!Common._warnedOnce[message]) {
6126            Common.warn(message);
6127            Common._warnedOnce[message] = true;
6128        }
6129    };
6130
6131    /**
6132     * Shows a deprecated console warning when the function on the given object is called.
6133     * The target function will be replaced with a new function that first shows the warning
6134     * and then calls the original function.
6135     * @method deprecated
6136     * @param {object} obj The object or module
6137     * @param {string} name The property name of the function on obj
6138     * @param {string} warning The one-time message to show if the function is called
6139     */
6140    Common.deprecated = function(obj, prop, warning) {
6141        obj[prop] = Common.chain(function() {
6142            Common.warnOnce('🔅 deprecated 🔅', warning);
6143        }, obj[prop]);
6144    };
6145
6146    /**
6147     * Returns the next unique sequential ID.
6148     * @method nextId
6149     * @return {Number} Unique sequential ID
6150     */
6151    Common.nextId = function() {
6152        return Common._nextId++;
6153    };
6154
6155    /**
6156     * A cross browser compatible indexOf implementation.
6157     * @method indexOf
6158     * @param {array} haystack
6159     * @param {object} needle
6160     * @return {number} The position of needle in haystack, otherwise -1.
6161     */
6162    Common.indexOf = function(haystack, needle) {
6163        if (haystack.indexOf)
6164            return haystack.indexOf(needle);
6165
6166        for (var i = 0; i < haystack.length; i++) {
6167            if (haystack[i] === needle)
6168                return i;
6169        }
6170
6171        return -1;
6172    };
6173
6174    /**
6175     * A cross browser compatible array map implementation.
6176     * @method map
6177     * @param {array} list
6178     * @param {function} func
6179     * @return {array} Values from list transformed by func.
6180     */
6181    Common.map = function(list, func) {
6182        if (list.map) {
6183            return list.map(func);
6184        }
6185
6186        var mapped = [];
6187
6188        for (var i = 0; i < list.length; i += 1) {
6189            mapped.push(func(list[i]));
6190        }
6191
6192        return mapped;
6193    };
6194
6195    /**
6196     * Takes a directed graph and returns the partially ordered set of vertices in topological order.
6197     * Circular dependencies are allowed.
6198     * @method topologicalSort
6199     * @param {object} graph
6200     * @return {array} Partially ordered set of vertices in topological order.
6201     */
6202    Common.topologicalSort = function(graph) {
6203        // https://github.com/mgechev/javascript-algorithms
6204        // Copyright (c) Minko Gechev (MIT license)
6205        // Modifications: tidy formatting and naming
6206        var result = [],
6207            visited = [],
6208            temp = [];
6209
6210        for (var node in graph) {
6211            if (!visited[node] && !temp[node]) {
6212                Common._topologicalSort(node, visited, temp, graph, result);
6213            }
6214        }
6215
6216        return result;
6217    };
6218
6219    Common._topologicalSort = function(node, visited, temp, graph, result) {
6220        var neighbors = graph[node] || [];
6221        temp[node] = true;
6222
6223        for (var i = 0; i < neighbors.length; i += 1) {
6224            var neighbor = neighbors[i];
6225
6226            if (temp[neighbor]) {
6227                // skip circular dependencies
6228                continue;
6229            }
6230
6231            if (!visited[neighbor]) {
6232                Common._topologicalSort(neighbor, visited, temp, graph, result);
6233            }
6234        }
6235
6236        temp[node] = false;
6237        visited[node] = true;
6238
6239        result.push(node);
6240    };
6241
6242    /**
6243     * Takes _n_ functions as arguments and returns a new function that calls them in order.
6244     * The arguments applied when calling the new function will also be applied to every function passed.
6245     * The value of `this` refers to the last value returned in the chain that was not `undefined`.
6246     * Therefore if a passed function does not return a value, the previously returned value is maintained.
6247     * After all passed functions have been called the new function returns the last returned value (if any).
6248     * If any of the passed functions are a chain, then the chain will be flattened.
6249     * @method chain
6250     * @param ...funcs {function} The functions to chain.
6251     * @return {function} A new function that calls the passed functions in order.
6252     */
6253    Common.chain = function() {
6254        var funcs = [];
6255
6256        for (var i = 0; i < arguments.length; i += 1) {
6257            var func = arguments[i];
6258
6259            if (func._chained) {
6260                // flatten already chained functions
6261                funcs.push.apply(funcs, func._chained);
6262            } else {
6263                funcs.push(func);
6264            }
6265        }
6266
6267        var chain = function() {
6268            // https://github.com/GoogleChrome/devtools-docs/issues/53#issuecomment-51941358
6269            var lastResult,
6270                args = new Array(arguments.length);
6271
6272            for (var i = 0, l = arguments.length; i < l; i++) {
6273                args[i] = arguments[i];
6274            }
6275
6276            for (i = 0; i < funcs.length; i += 1) {
6277                var result = funcs[i].apply(lastResult, args);
6278
6279                if (typeof result !== 'undefined') {
6280                    lastResult = result;
6281                }
6282            }
6283
6284            return lastResult;
6285        };
6286
6287        chain._chained = funcs;
6288
6289        return chain;
6290    };
6291
6292    /**
6293     * Chains a function to excute before the original function on the given `path` relative to `base`.
6294     * See also docs for `Common.chain`.
6295     * @method chainPathBefore
6296     * @param {} base The base object
6297     * @param {string} path The path relative to `base`
6298     * @param {function} func The function to chain before the original
6299     * @return {function} The chained function that replaced the original
6300     */
6301    Common.chainPathBefore = function(base, path, func) {
6302        return Common.set(base, path, Common.chain(
6303            func,
6304            Common.get(base, path)
6305        ));
6306    };
6307
6308    /**
6309     * Chains a function to excute after the original function on the given `path` relative to `base`.
6310     * See also docs for `Common.chain`.
6311     * @method chainPathAfter
6312     * @param {} base The base object
6313     * @param {string} path The path relative to `base`
6314     * @param {function} func The function to chain after the original
6315     * @return {function} The chained function that replaced the original
6316     */
6317    Common.chainPathAfter = function(base, path, func) {
6318        return Common.set(base, path, Common.chain(
6319            Common.get(base, path),
6320            func
6321        ));
6322    };
6323
6324    /**
6325     * Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable
6326     * concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`.
6327     * @method setDecomp
6328     * @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module.
6329     */
6330    Common.setDecomp = function(decomp) {
6331        Common._decomp = decomp;
6332    };
6333
6334    /**
6335     * Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`,
6336     * otherwise returns the global `decomp` if set.
6337     * @method getDecomp
6338     * @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided.
6339     */
6340    Common.getDecomp = function() {
6341        // get user provided decomp if set
6342        var decomp = Common._decomp;
6343
6344        try {
6345            // otherwise from window global
6346            if (!decomp && typeof window !== 'undefined') {
6347                decomp = window.decomp;
6348            }
6349    
6350            // otherwise from node global
6351            if (!decomp && typeof global !== 'undefined') {
6352                decomp = global.decomp;
6353            }
6354        } catch (e) {
6355            // decomp not available
6356            decomp = null;
6357        }
6358
6359        return decomp;
6360    };
6361})();
6362
6363
6364/***/ }),
6365/* 1 */
6366/***/ (function(module, exports) {
6367
6368/**
6369* The `Matter.Bounds` module contains methods for creating and manipulating axis-aligned bounding boxes (AABB).
6370*
6371* @class Bounds
6372*/
6373
6374var Bounds = {};
6375
6376module.exports = Bounds;
6377
6378(function() {
6379
6380    /**
6381     * Creates a new axis-aligned bounding box (AABB) for the given vertices.
6382     * @method create
6383     * @param {vertices} vertices
6384     * @return {bounds} A new bounds object
6385     */
6386    Bounds.create = function(vertices) {
6387        var bounds = { 
6388            min: { x: 0, y: 0 }, 
6389            max: { x: 0, y: 0 }
6390        };
6391
6392        if (vertices)
6393            Bounds.update(bounds, vertices);
6394        
6395        return bounds;
6396    };
6397
6398    /**
6399     * Updates bounds using the given vertices and extends the bounds given a velocity.
6400     * @method update
6401     * @param {bounds} bounds
6402     * @param {vertices} vertices
6403     * @param {vector} velocity
6404     */
6405    Bounds.update = function(bounds, vertices, velocity) {
6406        bounds.min.x = Infinity;
6407        bounds.max.x = -Infinity;
6408        bounds.min.y = Infinity;
6409        bounds.max.y = -Infinity;
6410
6411        for (var i = 0; i < vertices.length; i++) {
6412            var vertex = vertices[i];
6413            if (vertex.x > bounds.max.x) bounds.max.x = vertex.x;
6414            if (vertex.x < bounds.min.x) bounds.min.x = vertex.x;
6415            if (vertex.y > bounds.max.y) bounds.max.y = vertex.y;
6416            if (vertex.y < bounds.min.y) bounds.min.y = vertex.y;
6417        }
6418        
6419        if (velocity) {
6420            if (velocity.x > 0) {
6421                bounds.max.x += velocity.x;
6422            } else {
6423                bounds.min.x += velocity.x;
6424            }
6425            
6426            if (velocity.y > 0) {
6427                bounds.max.y += velocity.y;
6428            } else {
6429                bounds.min.y += velocity.y;
6430            }
6431        }
6432    };
6433
6434    /**
6435     * Returns true if the bounds contains the given point.
6436     * @method contains
6437     * @param {bounds} bounds
6438     * @param {vector} point
6439     * @return {boolean} True if the bounds contain the point, otherwise false
6440     */
6441    Bounds.contains = function(bounds, point) {
6442        return point.x >= bounds.min.x && point.x <= bounds.max.x 
6443               && point.y >= bounds.min.y && point.y <= bounds.max.y;
6444    };
6445
6446    /**
6447     * Returns true if the two bounds intersect.
6448     * @method overlaps
6449     * @param {bounds} boundsA
6450     * @param {bounds} boundsB
6451     * @return {boolean} True if the bounds overlap, otherwise false
6452     */
6453    Bounds.overlaps = function(boundsA, boundsB) {
6454        return (boundsA.min.x <= boundsB.max.x && boundsA.max.x >= boundsB.min.x
6455                && boundsA.max.y >= boundsB.min.y && boundsA.min.y <= boundsB.max.y);
6456    };
6457
6458    /**
6459     * Translates the bounds by the given vector.
6460     * @method translate
6461     * @param {bounds} bounds
6462     * @param {vector} vector
6463     */
6464    Bounds.translate = function(bounds, vector) {
6465        bounds.min.x += vector.x;
6466        bounds.max.x += vector.x;
6467        bounds.min.y += vector.y;
6468        bounds.max.y += vector.y;
6469    };
6470
6471    /**
6472     * Shifts the bounds to the given position.
6473     * @method shift
6474     * @param {bounds} bounds
6475     * @param {vector} position
6476     */
6477    Bounds.shift = function(bounds, position) {
6478        var deltaX = bounds.max.x - bounds.min.x,
6479            deltaY = bounds.max.y - bounds.min.y;
6480            
6481        bounds.min.x = position.x;
6482        bounds.max.x = position.x + deltaX;
6483        bounds.min.y = position.y;
6484        bounds.max.y = position.y + deltaY;
6485    };
6486    
6487})();
6488
6489
6490/***/ }),
6491/* 2 */
6492/***/ (function(module, exports) {
6493
6494/**
6495* The `Matter.Vector` module contains methods for creating and manipulating vectors.
6496* Vectors are the basis of all the geometry related operations in the engine.
6497* A `Matter.Vector` object is of the form `{ x: 0, y: 0 }`.
6498*
6499* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
6500*
6501* @class Vector
6502*/
6503
6504// TODO: consider params for reusing vector objects
6505
6506var Vector = {};
6507
6508module.exports = Vector;
6509
6510(function() {
6511
6512    /**
6513     * Creates a new vector.
6514     * @method create
6515     * @param {number} x
6516     * @param {number} y
6517     * @return {vector} A new vector
6518     */
6519    Vector.create = function(x, y) {
6520        return { x: x || 0, y: y || 0 };
6521    };
6522
6523    /**
6524     * Returns a new vector with `x` and `y` copied from the given `vector`.
6525     * @method clone
6526     * @param {vector} vector
6527     * @return {vector} A new cloned vector
6528     */
6529    Vector.clone = function(vector) {
6530        return { x: vector.x, y: vector.y };
6531    };
6532
6533    /**
6534     * Returns the magnitude (length) of a vector.
6535     * @method magnitude
6536     * @param {vector} vector
6537     * @return {number} The magnitude of the vector
6538     */
6539    Vector.magnitude = function(vector) {
6540        return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y));
6541    };
6542
6543    /**
6544     * Returns the magnitude (length) of a vector (therefore saving a `sqrt` operation).
6545     * @method magnitudeSquared
6546     * @param {vector} vector
6547     * @return {number} The squared magnitude of the vector
6548     */
6549    Vector.magnitudeSquared = function(vector) {
6550        return (vector.x * vector.x) + (vector.y * vector.y);
6551    };
6552
6553    /**
6554     * Rotates the vector about (0, 0) by specified angle.
6555     * @method rotate
6556     * @param {vector} vector
6557     * @param {number} angle
6558     * @param {vector} [output]
6559     * @return {vector} The vector rotated about (0, 0)
6560     */
6561    Vector.rotate = function(vector, angle, output) {
6562        var cos = Math.cos(angle), sin = Math.sin(angle);
6563        if (!output) output = {};
6564        var x = vector.x * cos - vector.y * sin;
6565        output.y = vector.x * sin + vector.y * cos;
6566        output.x = x;
6567        return output;
6568    };
6569
6570    /**
6571     * Rotates the vector about a specified point by specified angle.
6572     * @method rotateAbout
6573     * @param {vector} vector
6574     * @param {number} angle
6575     * @param {vector} point
6576     * @param {vector} [output]
6577     * @return {vector} A new vector rotated about the point
6578     */
6579    Vector.rotateAbout = function(vector, angle, point, output) {
6580        var cos = Math.cos(angle), sin = Math.sin(angle);
6581        if (!output) output = {};
6582        var x = point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin);
6583        output.y = point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos);
6584        output.x = x;
6585        return output;
6586    };
6587
6588    /**
6589     * Normalises a vector (such that its magnitude is `1`).
6590     * @method normalise
6591     * @param {vector} vector
6592     * @return {vector} A new vector normalised
6593     */
6594    Vector.normalise = function(vector) {
6595        var magnitude = Vector.magnitude(vector);
6596        if (magnitude === 0)
6597            return { x: 0, y: 0 };
6598        return { x: vector.x / magnitude, y: vector.y / magnitude };
6599    };
6600
6601    /**
6602     * Returns the dot-product of two vectors.
6603     * @method dot
6604     * @param {vector} vectorA
6605     * @param {vector} vectorB
6606     * @return {number} The dot product of the two vectors
6607     */
6608    Vector.dot = function(vectorA, vectorB) {
6609        return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y);
6610    };
6611
6612    /**
6613     * Returns the cross-product of two vectors.
6614     * @method cross
6615     * @param {vector} vectorA
6616     * @param {vector} vectorB
6617     * @return {number} The cross product of the two vectors
6618     */
6619    Vector.cross = function(vectorA, vectorB) {
6620        return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x);
6621    };
6622
6623    /**
6624     * Returns the cross-product of three vectors.
6625     * @method cross3
6626     * @param {vector} vectorA
6627     * @param {vector} vectorB
6628     * @param {vector} vectorC
6629     * @return {number} The cross product of the three vectors
6630     */
6631    Vector.cross3 = function(vectorA, vectorB, vectorC) {
6632        return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x);
6633    };
6634
6635    /**
6636     * Adds the two vectors.
6637     * @method add
6638     * @param {vector} vectorA
6639     * @param {vector} vectorB
6640     * @param {vector} [output]
6641     * @return {vector} A new vector of vectorA and vectorB added
6642     */
6643    Vector.add = function(vectorA, vectorB, output) {
6644        if (!output) output = {};
6645        output.x = vectorA.x + vectorB.x;
6646        output.y = vectorA.y + vectorB.y;
6647        return output;
6648    };
6649
6650    /**
6651     * Subtracts the two vectors.
6652     * @method sub
6653     * @param {vector} vectorA
6654     * @param {vector} vectorB
6655     * @param {vector} [output]
6656     * @return {vector} A new vector of vectorA and vectorB subtracted
6657     */
6658    Vector.sub = function(vectorA, vectorB, output) {
6659        if (!output) output = {};
6660        output.x = vectorA.x - vectorB.x;
6661        output.y = vectorA.y - vectorB.y;
6662        return output;
6663    };
6664
6665    /**
6666     * Multiplies a vector and a scalar.
6667     * @method mult
6668     * @param {vector} vector
6669     * @param {number} scalar
6670     * @return {vector} A new vector multiplied by scalar
6671     */
6672    Vector.mult = function(vector, scalar) {
6673        return { x: vector.x * scalar, y: vector.y * scalar };
6674    };
6675
6676    /**
6677     * Divides a vector and a scalar.
6678     * @method div
6679     * @param {vector} vector
6680     * @param {number} scalar
6681     * @return {vector} A new vector divided by scalar
6682     */
6683    Vector.div = function(vector, scalar) {
6684        return { x: vector.x / scalar, y: vector.y / scalar };
6685    };
6686
6687    /**
6688     * Returns the perpendicular vector. Set `negate` to true for the perpendicular in the opposite direction.
6689     * @method perp
6690     * @param {vector} vector
6691     * @param {bool} [negate=false]
6692     * @return {vector} The perpendicular vector
6693     */
6694    Vector.perp = function(vector, negate) {
6695        negate = negate === true ? -1 : 1;
6696        return { x: negate * -vector.y, y: negate * vector.x };
6697    };
6698
6699    /**
6700     * Negates both components of a vector such that it points in the opposite direction.
6701     * @method neg
6702     * @param {vector} vector
6703     * @return {vector} The negated vector
6704     */
6705    Vector.neg = function(vector) {
6706        return { x: -vector.x, y: -vector.y };
6707    };
6708
6709    /**
6710     * Returns the angle between the vector `vectorB - vectorA` and the x-axis in radians.
6711     * @method angle
6712     * @param {vector} vectorA
6713     * @param {vector} vectorB
6714     * @return {number} The angle in radians
6715     */
6716    Vector.angle = function(vectorA, vectorB) {
6717        return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x);
6718    };
6719
6720    /**
6721     * Temporary vector pool (not thread-safe).
6722     * @property _temp
6723     * @type {vector[]}
6724     * @private
6725     */
6726    Vector._temp = [
6727        Vector.create(), Vector.create(), 
6728        Vector.create(), Vector.create(), 
6729        Vector.create(), Vector.create()
6730    ];
6731
6732})();
6733
6734/***/ }),
6735/* 3 */
6736/***/ (function(module, exports, __webpack_require__) {
6737
6738/**
6739* The `Matter.Vertices` module contains methods for creating and manipulating sets of vertices.
6740* A set of vertices is an array of `Matter.Vector` with additional indexing properties inserted by `Vertices.create`.
6741* A `Matter.Body` maintains a set of vertices to represent the shape of the object (its convex hull).
6742*
6743* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
6744*
6745* @class Vertices
6746*/
6747
6748var Vertices = {};
6749
6750module.exports = Vertices;
6751
6752var Vector = __webpack_require__(2);
6753var Common = __webpack_require__(0);
6754
6755(function() {
6756
6757    /**
6758     * Creates a new set of `Matter.Body` compatible vertices.
6759     * The `points` argument accepts an array of `Matter.Vector` points orientated around the origin `(0, 0)`, for example:
6760     *
6761     *     [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }]
6762     *
6763     * The `Vertices.create` method returns a new array of vertices, which are similar to Matter.Vector objects,
6764     * but with some additional references required for efficient collision detection routines.
6765     *
6766     * Vertices must be specified in clockwise order.
6767     *
6768     * Note that the `body` argument is not optional, a `Matter.Body` reference must be provided.
6769     *
6770     * @method create
6771     * @param {vector[]} points
6772     * @param {body} body
6773     */
6774    Vertices.create = function(points, body) {
6775        var vertices = [];
6776
6777        for (var i = 0; i < points.length; i++) {
6778            var point = points[i],
6779                vertex = {
6780                    x: point.x,
6781                    y: point.y,
6782                    index: i,
6783                    body: body,
6784                    isInternal: false
6785                };
6786
6787            vertices.push(vertex);
6788        }
6789
6790        return vertices;
6791    };
6792
6793    /**
6794     * Parses a string containing ordered x y pairs separated by spaces (and optionally commas), 
6795     * into a `Matter.Vertices` object for the given `Matter.Body`.
6796     * For parsing SVG paths, see `Svg.pathToVertices`.
6797     * @method fromPath
6798     * @param {string} path
6799     * @param {body} body
6800     * @return {vertices} vertices
6801     */
6802    Vertices.fromPath = function(path, body) {
6803        var pathPattern = /L?\s*([-\d.e]+)[\s,]*([-\d.e]+)*/ig,
6804            points = [];
6805
6806        path.replace(pathPattern, function(match, x, y) {
6807            points.push({ x: parseFloat(x), y: parseFloat(y) });
6808        });
6809
6810        return Vertices.create(points, body);
6811    };
6812
6813    /**
6814     * Returns the centre (centroid) of the set of vertices.
6815     * @method centre
6816     * @param {vertices} vertices
6817     * @return {vector} The centre point
6818     */
6819    Vertices.centre = function(vertices) {
6820        var area = Vertices.area(vertices, true),
6821            centre = { x: 0, y: 0 },
6822            cross,
6823            temp,
6824            j;
6825
6826        for (var i = 0; i < vertices.length; i++) {
6827            j = (i + 1) % vertices.length;
6828            cross = Vector.cross(vertices[i], vertices[j]);
6829            temp = Vector.mult(Vector.add(vertices[i], vertices[j]), cross);
6830            centre = Vector.add(centre, temp);
6831        }
6832
6833        return Vector.div(centre, 6 * area);
6834    };
6835
6836    /**
6837     * Returns the average (mean) of the set of vertices.
6838     * @method mean
6839     * @param {vertices} vertices
6840     * @return {vector} The average point
6841     */
6842    Vertices.mean = function(vertices) {
6843        var average = { x: 0, y: 0 };
6844
6845        for (var i = 0; i < vertices.length; i++) {
6846            average.x += vertices[i].x;
6847            average.y += vertices[i].y;
6848        }
6849
6850        return Vector.div(average, vertices.length);
6851    };
6852
6853    /**
6854     * Returns the area of the set of vertices.
6855     * @method area
6856     * @param {vertices} vertices
6857     * @param {bool} signed
6858     * @return {number} The area
6859     */
6860    Vertices.area = function(vertices, signed) {
6861        var area = 0,
6862            j = vertices.length - 1;
6863
6864        for (var i = 0; i < vertices.length; i++) {
6865            area += (vertices[j].x - vertices[i].x) * (vertices[j].y + vertices[i].y);
6866            j = i;
6867        }
6868
6869        if (signed)
6870            return area / 2;
6871
6872        return Math.abs(area) / 2;
6873    };
6874
6875    /**
6876     * Returns the moment of inertia (second moment of area) of the set of vertices given the total mass.
6877     * @method inertia
6878     * @param {vertices} vertices
6879     * @param {number} mass
6880     * @return {number} The polygon's moment of inertia
6881     */
6882    Vertices.inertia = function(vertices, mass) {
6883        var numerator = 0,
6884            denominator = 0,
6885            v = vertices,
6886            cross,
6887            j;
6888
6889        // find the polygon's moment of inertia, using second moment of area
6890        // from equations at http://www.physicsforums.com/showthread.php?t=25293
6891        for (var n = 0; n < v.length; n++) {
6892            j = (n + 1) % v.length;
6893            cross = Math.abs(Vector.cross(v[j], v[n]));
6894            numerator += cross * (Vector.dot(v[j], v[j]) + Vector.dot(v[j], v[n]) + Vector.dot(v[n], v[n]));
6895            denominator += cross;
6896        }
6897
6898        return (mass / 6) * (numerator / denominator);
6899    };
6900
6901    /**
6902     * Translates the set of vertices in-place.
6903     * @method translate
6904     * @param {vertices} vertices
6905     * @param {vector} vector
6906     * @param {number} scalar
6907     */
6908    Vertices.translate = function(vertices, vector, scalar) {
6909        scalar = typeof scalar !== 'undefined' ? scalar : 1;
6910
6911        var verticesLength = vertices.length,
6912            translateX = vector.x * scalar,
6913            translateY = vector.y * scalar,
6914            i;
6915        
6916        for (i = 0; i < verticesLength; i++) {
6917            vertices[i].x += translateX;
6918            vertices[i].y += translateY;
6919        }
6920
6921        return vertices;
6922    };
6923
6924    /**
6925     * Rotates the set of vertices in-place.
6926     * @method rotate
6927     * @param {vertices} vertices
6928     * @param {number} angle
6929     * @param {vector} point
6930     */
6931    Vertices.rotate = function(vertices, angle, point) {
6932        if (angle === 0)
6933            return;
6934
6935        var cos = Math.cos(angle),
6936            sin = Math.sin(angle),
6937            pointX = point.x,
6938            pointY = point.y,
6939            verticesLength = vertices.length,
6940            vertex,
6941            dx,
6942            dy,
6943            i;
6944
6945        for (i = 0; i < verticesLength; i++) {
6946            vertex = vertices[i];
6947            dx = vertex.x - pointX;
6948            dy = vertex.y - pointY;
6949            vertex.x = pointX + (dx * cos - dy * sin);
6950            vertex.y = pointY + (dx * sin + dy * cos);
6951        }
6952
6953        return vertices;
6954    };
6955
6956    /**
6957     * Returns `true` if the `point` is inside the set of `vertices`.
6958     * @method contains
6959     * @param {vertices} vertices
6960     * @param {vector} point
6961     * @return {boolean} True if the vertices contains point, otherwise false
6962     */
6963    Vertices.contains = function(vertices, point) {
6964        var pointX = point.x,
6965            pointY = point.y,
6966            verticesLength = vertices.length,
6967            vertex = vertices[verticesLength - 1],
6968            nextVertex;
6969
6970        for (var i = 0; i < verticesLength; i++) {
6971            nextVertex = vertices[i];
6972
6973            if ((pointX - vertex.x) * (nextVertex.y - vertex.y) 
6974                + (pointY - vertex.y) * (vertex.x - nextVertex.x) > 0) {
6975                return false;
6976            }
6977
6978            vertex = nextVertex;
6979        }
6980
6981        return true;
6982    };
6983
6984    /**
6985     * Scales the vertices from a point (default is centre) in-place.
6986     * @method scale
6987     * @param {vertices} vertices
6988     * @param {number} scaleX
6989     * @param {number} scaleY
6990     * @param {vector} point
6991     */
6992    Vertices.scale = function(vertices, scaleX, scaleY, point) {
6993        if (scaleX === 1 && scaleY === 1)
6994            return vertices;
6995
6996        point = point || Vertices.centre(vertices);
6997
6998        var vertex,
6999            delta;
7000
7001        for (var i = 0; i < vertices.length; i++) {
7002            vertex = vertices[i];
7003            delta = Vector.sub(vertex, point);
7004            vertices[i].x = point.x + delta.x * scaleX;
7005            vertices[i].y = point.y + delta.y * scaleY;
7006        }
7007
7008        return vertices;
7009    };
7010
7011    /**
7012     * Chamfers a set of vertices by giving them rounded corners, returns a new set of vertices.
7013     * The radius parameter is a single number or an array to specify the radius for each vertex.
7014     * @method chamfer
7015     * @param {vertices} vertices
7016     * @param {number[]} radius
7017     * @param {number} quality
7018     * @param {number} qualityMin
7019     * @param {number} qualityMax
7020     */
7021    Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {
7022        if (typeof radius === 'number') {
7023            radius = [radius];
7024        } else {
7025            radius = radius || [8];
7026        }
7027
7028        // quality defaults to -1, which is auto
7029        quality = (typeof quality !== 'undefined') ? quality : -1;
7030        qualityMin = qualityMin || 2;
7031        qualityMax = qualityMax || 14;
7032
7033        var newVertices = [];
7034
7035        for (var i = 0; i < vertices.length; i++) {
7036            var prevVertex = vertices[i - 1 >= 0 ? i - 1 : vertices.length - 1],
7037                vertex = vertices[i],
7038                nextVertex = vertices[(i + 1) % vertices.length],
7039                currentRadius = radius[i < radius.length ? i : radius.length - 1];
7040
7041            if (currentRadius === 0) {
7042                newVertices.push(vertex);
7043                continue;
7044            }
7045
7046            var prevNormal = Vector.normalise({ 
7047                x: vertex.y - prevVertex.y, 
7048                y: prevVertex.x - vertex.x
7049            });
7050
7051            var nextNormal = Vector.normalise({ 
7052                x: nextVertex.y - vertex.y, 
7053                y: vertex.x - nextVertex.x
7054            });
7055
7056            var diagonalRadius = Math.sqrt(2 * Math.pow(currentRadius, 2)),
7057                radiusVector = Vector.mult(Common.clone(prevNormal), currentRadius),
7058                midNormal = Vector.normalise(Vector.mult(Vector.add(prevNormal, nextNormal), 0.5)),
7059                scaledVertex = Vector.sub(vertex, Vector.mult(midNormal, diagonalRadius));
7060
7061            var precision = quality;
7062
7063            if (quality === -1) {
7064                // automatically decide precision
7065                precision = Math.pow(currentRadius, 0.32) * 1.75;
7066            }
7067
7068            precision = Common.clamp(precision, qualityMin, qualityMax);
7069
7070            // use an even value for precision, more likely to reduce axes by using symmetry
7071            if (precision % 2 === 1)
7072                precision += 1;
7073
7074            var alpha = Math.acos(Vector.dot(prevNormal, nextNormal)),
7075                theta = alpha / precision;
7076
7077            for (var j = 0; j < precision; j++) {
7078                newVertices.push(Vector.add(Vector.rotate(radiusVector, theta * j), scaledVertex));
7079            }
7080        }
7081
7082        return newVertices;
7083    };
7084
7085    /**
7086     * Sorts the input vertices into clockwise order in place.
7087     * @method clockwiseSort
7088     * @param {vertices} vertices
7089     * @return {vertices} vertices
7090     */
7091    Vertices.clockwiseSort = function(vertices) {
7092        var centre = Vertices.mean(vertices);
7093
7094        vertices.sort(function(vertexA, vertexB) {
7095            return Vector.angle(centre, vertexA) - Vector.angle(centre, vertexB);
7096        });
7097
7098        return vertices;
7099    };
7100
7101    /**
7102     * Returns true if the vertices form a convex shape (vertices must be in clockwise order).
7103     * @method isConvex
7104     * @param {vertices} vertices
7105     * @return {bool} `true` if the `vertices` are convex, `false` if not (or `null` if not computable).
7106     */
7107    Vertices.isConvex = function(vertices) {
7108        // http://paulbourke.net/geometry/polygonmesh/
7109        // Copyright (c) Paul Bourke (use permitted)
7110
7111        var flag = 0,
7112            n = vertices.length,
7113            i,
7114            j,
7115            k,
7116            z;
7117
7118        if (n < 3)
7119            return null;
7120
7121        for (i = 0; i < n; i++) {
7122            j = (i + 1) % n;
7123            k = (i + 2) % n;
7124            z = (vertices[j].x - vertices[i].x) * (vertices[k].y - vertices[j].y);
7125            z -= (vertices[j].y - vertices[i].y) * (vertices[k].x - vertices[j].x);
7126
7127            if (z < 0) {
7128                flag |= 1;
7129            } else if (z > 0) {
7130                flag |= 2;
7131            }
7132
7133            if (flag === 3) {
7134                return false;
7135            }
7136        }
7137
7138        if (flag !== 0){
7139            return true;
7140        } else {
7141            return null;
7142        }
7143    };
7144
7145    /**
7146     * Returns the convex hull of the input vertices as a new array of points.
7147     * @method hull
7148     * @param {vertices} vertices
7149     * @return [vertex] vertices
7150     */
7151    Vertices.hull = function(vertices) {
7152        // http://geomalgorithms.com/a10-_hull-1.html
7153
7154        var upper = [],
7155            lower = [], 
7156            vertex,
7157            i;
7158
7159        // sort vertices on x-axis (y-axis for ties)
7160        vertices = vertices.slice(0);
7161        vertices.sort(function(vertexA, vertexB) {
7162            var dx = vertexA.x - vertexB.x;
7163            return dx !== 0 ? dx : vertexA.y - vertexB.y;
7164        });
7165
7166        // build lower hull
7167        for (i = 0; i < vertices.length; i += 1) {
7168            vertex = vertices[i];
7169
7170            while (lower.length >= 2 
7171                   && Vector.cross3(lower[lower.length - 2], lower[lower.length - 1], vertex) <= 0) {
7172                lower.pop();
7173            }
7174
7175            lower.push(vertex);
7176        }
7177
7178        // build upper hull
7179        for (i = vertices.length - 1; i >= 0; i -= 1) {
7180            vertex = vertices[i];
7181
7182            while (upper.length >= 2 
7183                   && Vector.cross3(upper[upper.length - 2], upper[upper.length - 1], vertex) <= 0) {
7184                upper.pop();
7185            }
7186
7187            upper.push(vertex);
7188        }
7189
7190        // concatenation of the lower and upper hulls gives the convex hull
7191        // omit last points because they are repeated at the beginning of the other list
7192        upper.pop();
7193        lower.pop();
7194
7195        return upper.concat(lower);
7196    };
7197
7198})();
7199
7200
7201/***/ }),
7202/* 4 */
7203/***/ (function(module, exports, __webpack_require__) {
7204
7205/**
7206* The `Matter.Body` module contains methods for creating and manipulating rigid bodies.
7207* For creating bodies with common configurations such as rectangles, circles and other polygons see the module `Matter.Bodies`.
7208*
7209* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
7210
7211* @class Body
7212*/
7213
7214var Body = {};
7215
7216module.exports = Body;
7217
7218var Vertices = __webpack_require__(3);
7219var Vector = __webpack_require__(2);
7220var Sleeping = __webpack_require__(7);
7221var Common = __webpack_require__(0);
7222var Bounds = __webpack_require__(1);
7223var Axes = __webpack_require__(11);
7224
7225(function() {
7226
7227    Body._timeCorrection = true;
7228    Body._inertiaScale = 4;
7229    Body._nextCollidingGroupId = 1;
7230    Body._nextNonCollidingGroupId = -1;
7231    Body._nextCategory = 0x0001;
7232    Body._baseDelta = 1000 / 60;
7233
7234    /**
7235     * Creates a new rigid body model. The options parameter is an object that specifies any properties you wish to override the defaults.
7236     * All properties have default values, and many are pre-calculated automatically based on other properties.
7237     * Vertices must be specified in clockwise order.
7238     * See the properties section below for detailed information on what you can pass via the `options` object.
7239     * @method create
7240     * @param {} options
7241     * @return {body} body
7242     */
7243    Body.create = function(options) {
7244        var defaults = {
7245            id: Common.nextId(),
7246            type: 'body',
7247            label: 'Body',
7248            parts: [],
7249            plugin: {},
7250            angle: 0,
7251            vertices: Vertices.fromPath('L 0 0 L 40 0 L 40 40 L 0 40'),
7252            position: { x: 0, y: 0 },
7253            force: { x: 0, y: 0 },
7254            torque: 0,
7255            positionImpulse: { x: 0, y: 0 },
7256            constraintImpulse: { x: 0, y: 0, angle: 0 },
7257            totalContacts: 0,
7258            speed: 0,
7259            angularSpeed: 0,
7260            velocity: { x: 0, y: 0 },
7261            angularVelocity: 0,
7262            isSensor: false,
7263            isStatic: false,
7264            isSleeping: false,
7265            motion: 0,
7266            sleepThreshold: 60,
7267            density: 0.001,
7268            restitution: 0,
7269            friction: 0.1,
7270            frictionStatic: 0.5,
7271            frictionAir: 0.01,
7272            collisionFilter: {
7273                category: 0x0001,
7274                mask: 0xFFFFFFFF,
7275                group: 0
7276            },
7277            slop: 0.05,
7278            timeScale: 1,
7279            render: {
7280                visible: true,
7281                opacity: 1,
7282                strokeStyle: null,
7283                fillStyle: null,
7284                lineWidth: null,
7285                sprite: {
7286                    xScale: 1,
7287                    yScale: 1,
7288                    xOffset: 0,
7289                    yOffset: 0
7290                }
7291            },
7292            events: null,
7293            bounds: null,
7294            chamfer: null,
7295            circleRadius: 0,
7296            positionPrev: null,
7297            anglePrev: 0,
7298            parent: null,
7299            axes: null,
7300            area: 0,
7301            mass: 0,
7302            inertia: 0,
7303            deltaTime: 1000 / 60,
7304            _original: null
7305        };
7306
7307        var body = Common.extend(defaults, options);
7308
7309        _initProperties(body, options);
7310
7311        return body;
7312    };
7313
7314    /**
7315     * Returns the next unique group index for which bodies will collide.
7316     * If `isNonColliding` is `true`, returns the next unique group index for which bodies will _not_ collide.
7317     * See `body.collisionFilter` for more information.
7318     * @method nextGroup
7319     * @param {bool} [isNonColliding=false]
7320     * @return {Number} Unique group index
7321     */
7322    Body.nextGroup = function(isNonColliding) {
7323        if (isNonColliding)
7324            return Body._nextNonCollidingGroupId--;
7325
7326        return Body._nextCollidingGroupId++;
7327    };
7328
7329    /**
7330     * Returns the next unique category bitfield (starting after the initial default category `0x0001`).
7331     * There are 32 available. See `body.collisionFilter` for more information.
7332     * @method nextCategory
7333     * @return {Number} Unique category bitfield
7334     */
7335    Body.nextCategory = function() {
7336        Body._nextCategory = Body._nextCategory << 1;
7337        return Body._nextCategory;
7338    };
7339
7340    /**
7341     * Initialises body properties.
7342     * @method _initProperties
7343     * @private
7344     * @param {body} body
7345     * @param {} [options]
7346     */
7347    var _initProperties = function(body, options) {
7348        options = options || {};
7349
7350        // init required properties (order is important)
7351        Body.set(body, {
7352            bounds: body.bounds || Bounds.create(body.vertices),
7353            positionPrev: body.positionPrev || Vector.clone(body.position),
7354            anglePrev: body.anglePrev || body.angle,
7355            vertices: body.vertices,
7356            parts: body.parts || [body],
7357            isStatic: body.isStatic,
7358            isSleeping: body.isSleeping,
7359            parent: body.parent || body
7360        });
7361
7362        Vertices.rotate(body.vertices, body.angle, body.position);
7363        Axes.rotate(body.axes, body.angle);
7364        Bounds.update(body.bounds, body.vertices, body.velocity);
7365
7366        // allow options to override the automatically calculated properties
7367        Body.set(body, {
7368            axes: options.axes || body.axes,
7369            area: options.area || body.area,
7370            mass: options.mass || body.mass,
7371            inertia: options.inertia || body.inertia
7372        });
7373
7374        // render properties
7375        var defaultFillStyle = (body.isStatic ? '#14151f' : Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1'])),
7376            defaultStrokeStyle = body.isStatic ? '#555' : '#ccc',
7377            defaultLineWidth = body.isStatic && body.render.fillStyle === null ? 1 : 0;
7378        body.render.fillStyle = body.render.fillStyle || defaultFillStyle;
7379        body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle;
7380        body.render.lineWidth = body.render.lineWidth || defaultLineWidth;
7381        body.render.sprite.xOffset += -(body.bounds.min.x - body.position.x) / (body.bounds.max.x - body.bounds.min.x);
7382        body.render.sprite.yOffset += -(body.bounds.min.y - body.position.y) / (body.bounds.max.y - body.bounds.min.y);
7383    };
7384
7385    /**
7386     * Given a property and a value (or map of), sets the property(s) on the body, using the appropriate setter functions if they exist.
7387     * Prefer to use the actual setter functions in performance critical situations.
7388     * @method set
7389     * @param {body} body
7390     * @param {} settings A property name (or map of properties and values) to set on the body.
7391     * @param {} value The value to set if `settings` is a single property name.
7392     */
7393    Body.set = function(body, settings, value) {
7394        var property;
7395
7396        if (typeof settings === 'string') {
7397            property = settings;
7398            settings = {};
7399            settings[property] = value;
7400        }
7401
7402        for (property in settings) {
7403            if (!Object.prototype.hasOwnProperty.call(settings, property))
7404                continue;
7405
7406            value = settings[property];
7407            switch (property) {
7408
7409            case 'isStatic':
7410                Body.setStatic(body, value);
7411                break;
7412            case 'isSleeping':
7413                Sleeping.set(body, value);
7414                break;
7415            case 'mass':
7416                Body.setMass(body, value);
7417                break;
7418            case 'density':
7419                Body.setDensity(body, value);
7420                break;
7421            case 'inertia':
7422                Body.setInertia(body, value);
7423                break;
7424            case 'vertices':
7425                Body.setVertices(body, value);
7426                break;
7427            case 'position':
7428                Body.setPosition(body, value);
7429                break;
7430            case 'angle':
7431                Body.setAngle(body, value);
7432                break;
7433            case 'velocity':
7434                Body.setVelocity(body, value);
7435                break;
7436            case 'angularVelocity':
7437                Body.setAngularVelocity(body, value);
7438                break;
7439            case 'speed':
7440                Body.setSpeed(body, value);
7441                break;
7442            case 'angularSpeed':
7443                Body.setAngularSpeed(body, value);
7444                break;
7445            case 'parts':
7446                Body.setParts(body, value);
7447                break;
7448            case 'centre':
7449                Body.setCentre(body, value);
7450                break;
7451            default:
7452                body[property] = value;
7453
7454            }
7455        }
7456    };
7457
7458    /**
7459     * Sets the body as static, including isStatic flag and setting mass and inertia to Infinity.
7460     * @method setStatic
7461     * @param {body} body
7462     * @param {bool} isStatic
7463     */
7464    Body.setStatic = function(body, isStatic) {
7465        for (var i = 0; i < body.parts.length; i++) {
7466            var part = body.parts[i];
7467
7468            if (isStatic) {
7469                if (!part.isStatic) {
7470                    part._original = {
7471                        restitution: part.restitution,
7472                        friction: part.friction,
7473                        mass: part.mass,
7474                        inertia: part.inertia,
7475                        density: part.density,
7476                        inverseMass: part.inverseMass,
7477                        inverseInertia: part.inverseInertia
7478                    };
7479                }
7480
7481                part.restitution = 0;
7482                part.friction = 1;
7483                part.mass = part.inertia = part.density = Infinity;
7484                part.inverseMass = part.inverseInertia = 0;
7485
7486                part.positionPrev.x = part.position.x;
7487                part.positionPrev.y = part.position.y;
7488                part.anglePrev = part.angle;
7489                part.angularVelocity = 0;
7490                part.speed = 0;
7491                part.angularSpeed = 0;
7492                part.motion = 0;
7493            } else if (part._original) {
7494                part.restitution = part._original.restitution;
7495                part.friction = part._original.friction;
7496                part.mass = part._original.mass;
7497                part.inertia = part._original.inertia;
7498                part.density = part._original.density;
7499                part.inverseMass = part._original.inverseMass;
7500                part.inverseInertia = part._original.inverseInertia;
7501
7502                part._original = null;
7503            }
7504
7505            part.isStatic = isStatic;
7506        }
7507    };
7508
7509    /**
7510     * Sets the mass of the body. Inverse mass, density and inertia are automatically updated to reflect the change.
7511     * @method setMass
7512     * @param {body} body
7513     * @param {number} mass
7514     */
7515    Body.setMass = function(body, mass) {
7516        var moment = body.inertia / (body.mass / 6);
7517        body.inertia = moment * (mass / 6);
7518        body.inverseInertia = 1 / body.inertia;
7519
7520        body.mass = mass;
7521        body.inverseMass = 1 / body.mass;
7522        body.density = body.mass / body.area;
7523    };
7524
7525    /**
7526     * Sets the density of the body. Mass and inertia are automatically updated to reflect the change.
7527     * @method setDensity
7528     * @param {body} body
7529     * @param {number} density
7530     */
7531    Body.setDensity = function(body, density) {
7532        Body.setMass(body, density * body.area);
7533        body.density = density;
7534    };
7535
7536    /**
7537     * Sets the moment of inertia of the body. This is the second moment of area in two dimensions.
7538     * Inverse inertia is automatically updated to reflect the change. Mass is not changed.
7539     * @method setInertia
7540     * @param {body} body
7541     * @param {number} inertia
7542     */
7543    Body.setInertia = function(body, inertia) {
7544        body.inertia = inertia;
7545        body.inverseInertia = 1 / body.inertia;
7546    };
7547
7548    /**
7549     * Sets the body's vertices and updates body properties accordingly, including inertia, area and mass (with respect to `body.density`).
7550     * Vertices will be automatically transformed to be orientated around their centre of mass as the origin.
7551     * They are then automatically translated to world space based on `body.position`.
7552     *
7553     * The `vertices` argument should be passed as an array of `Matter.Vector` points (or a `Matter.Vertices` array).
7554     * Vertices must form a convex hull. Concave vertices must be decomposed into convex parts.
7555     * 
7556     * @method setVertices
7557     * @param {body} body
7558     * @param {vector[]} vertices
7559     */
7560    Body.setVertices = function(body, vertices) {
7561        // change vertices
7562        if (vertices[0].body === body) {
7563            body.vertices = vertices;
7564        } else {
7565            body.vertices = Vertices.create(vertices, body);
7566        }
7567
7568        // update properties
7569        body.axes = Axes.fromVertices(body.vertices);
7570        body.area = Vertices.area(body.vertices);
7571        Body.setMass(body, body.density * body.area);
7572
7573        // orient vertices around the centre of mass at origin (0, 0)
7574        var centre = Vertices.centre(body.vertices);
7575        Vertices.translate(body.vertices, centre, -1);
7576
7577        // update inertia while vertices are at origin (0, 0)
7578        Body.setInertia(body, Body._inertiaScale * Vertices.inertia(body.vertices, body.mass));
7579
7580        // update geometry
7581        Vertices.translate(body.vertices, body.position);
7582        Bounds.update(body.bounds, body.vertices, body.velocity);
7583    };
7584
7585    /**
7586     * Sets the parts of the `body`. 
7587     * 
7588     * See `body.parts` for details and requirements on how parts are used.
7589     * 
7590     * See Bodies.fromVertices for a related utility.
7591     * 
7592     * This function updates `body` mass, inertia and centroid based on the parts geometry.  
7593     * Sets each `part.parent` to be this `body`.  
7594     * 
7595     * The convex hull is computed and set on this `body` (unless `autoHull` is `false`).  
7596     * Automatically ensures that the first part in `body.parts` is the `body`.
7597     * @method setParts
7598     * @param {body} body
7599     * @param {body[]} parts
7600     * @param {bool} [autoHull=true]
7601     */
7602    Body.setParts = function(body, parts, autoHull) {
7603        var i;
7604
7605        // add all the parts, ensuring that the first part is always the parent body
7606        parts = parts.slice(0);
7607        body.parts.length = 0;
7608        body.parts.push(body);
7609        body.parent = body;
7610
7611        for (i = 0; i < parts.length; i++) {
7612            var part = parts[i];
7613            if (part !== body) {
7614                part.parent = body;
7615                body.parts.push(part);
7616            }
7617        }
7618
7619        if (body.parts.length === 1)
7620            return;
7621
7622        autoHull = typeof autoHull !== 'undefined' ? autoHull : true;
7623
7624        // find the convex hull of all parts to set on the parent body
7625        if (autoHull) {
7626            var vertices = [];
7627            for (i = 0; i < parts.length; i++) {
7628                vertices = vertices.concat(parts[i].vertices);
7629            }
7630
7631            Vertices.clockwiseSort(vertices);
7632
7633            var hull = Vertices.hull(vertices),
7634                hullCentre = Vertices.centre(hull);
7635
7636            Body.setVertices(body, hull);
7637            Vertices.translate(body.vertices, hullCentre);
7638        }
7639
7640        // sum the properties of all compound parts of the parent body
7641        var total = Body._totalProperties(body);
7642
7643        body.area = total.area;
7644        body.parent = body;
7645        body.position.x = total.centre.x;
7646        body.position.y = total.centre.y;
7647        body.positionPrev.x = total.centre.x;
7648        body.positionPrev.y = total.centre.y;
7649
7650        Body.setMass(body, total.mass);
7651        Body.setInertia(body, total.inertia);
7652        Body.setPosition(body, total.centre);
7653    };
7654
7655    /**
7656     * Set the centre of mass of the body. 
7657     * The `centre` is a vector in world-space unless `relative` is set, in which case it is a translation.
7658     * The centre of mass is the point the body rotates about and can be used to simulate non-uniform density.
7659     * This is equal to moving `body.position` but not the `body.vertices`.
7660     * Invalid if the `centre` falls outside the body's convex hull.
7661     * @method setCentre
7662     * @param {body} body
7663     * @param {vector} centre
7664     * @param {bool} relative
7665     */
7666    Body.setCentre = function(body, centre, relative) {
7667        if (!relative) {
7668            body.positionPrev.x = centre.x - (body.position.x - body.positionPrev.x);
7669            body.positionPrev.y = centre.y - (body.position.y - body.positionPrev.y);
7670            body.position.x = centre.x;
7671            body.position.y = centre.y;
7672        } else {
7673            body.positionPrev.x += centre.x;
7674            body.positionPrev.y += centre.y;
7675            body.position.x += centre.x;
7676            body.position.y += centre.y;
7677        }
7678    };
7679
7680    /**
7681     * Sets the position of the body. By default velocity is unchanged.
7682     * If `updateVelocity` is `true` then velocity is inferred from the change in position.
7683     * @method setPosition
7684     * @param {body} body
7685     * @param {vector} position
7686     * @param {boolean} [updateVelocity=false]
7687     */
7688    Body.setPosition = function(body, position, updateVelocity) {
7689        var delta = Vector.sub(position, body.position);
7690
7691        if (updateVelocity) {
7692            body.positionPrev.x = body.position.x;
7693            body.positionPrev.y = body.position.y;
7694            body.velocity.x = delta.x;
7695            body.velocity.y = delta.y;
7696            body.speed = Vector.magnitude(delta);
7697        } else {
7698            body.positionPrev.x += delta.x;
7699            body.positionPrev.y += delta.y;
7700        }
7701
7702        for (var i = 0; i < body.parts.length; i++) {
7703            var part = body.parts[i];
7704            part.position.x += delta.x;
7705            part.position.y += delta.y;
7706            Vertices.translate(part.vertices, delta);
7707            Bounds.update(part.bounds, part.vertices, body.velocity);
7708        }
7709    };
7710
7711    /**
7712     * Sets the angle of the body. By default angular velocity is unchanged.
7713     * If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
7714     * @method setAngle
7715     * @param {body} body
7716     * @param {number} angle
7717     * @param {boolean} [updateVelocity=false]
7718     */
7719    Body.setAngle = function(body, angle, updateVelocity) {
7720        var delta = angle - body.angle;
7721        
7722        if (updateVelocity) {
7723            body.anglePrev = body.angle;
7724            body.angularVelocity = delta;
7725            body.angularSpeed = Math.abs(delta);
7726        } else {
7727            body.anglePrev += delta;
7728        }
7729
7730        for (var i = 0; i < body.parts.length; i++) {
7731            var part = body.parts[i];
7732            part.angle += delta;
7733            Vertices.rotate(part.vertices, delta, body.position);
7734            Axes.rotate(part.axes, delta);
7735            Bounds.update(part.bounds, part.vertices, body.velocity);
7736            if (i > 0) {
7737                Vector.rotateAbout(part.position, delta, body.position, part.position);
7738            }
7739        }
7740    };
7741
7742    /**
7743     * Sets the current linear velocity of the body.  
7744     * Affects body speed.
7745     * @method setVelocity
7746     * @param {body} body
7747     * @param {vector} velocity
7748     */
7749    Body.setVelocity = function(body, velocity) {
7750        var timeScale = body.deltaTime / Body._baseDelta;
7751        body.positionPrev.x = body.position.x - velocity.x * timeScale;
7752        body.positionPrev.y = body.position.y - velocity.y * timeScale;
7753        body.velocity.x = (body.position.x - body.positionPrev.x) / timeScale;
7754        body.velocity.y = (body.position.y - body.positionPrev.y) / timeScale;
7755        body.speed = Vector.magnitude(body.velocity);
7756    };
7757
7758    /**
7759     * Gets the current linear velocity of the body.
7760     * @method getVelocity
7761     * @param {body} body
7762     * @return {vector} velocity
7763     */
7764    Body.getVelocity = function(body) {
7765        var timeScale = Body._baseDelta / body.deltaTime;
7766
7767        return {
7768            x: (body.position.x - body.positionPrev.x) * timeScale,
7769            y: (body.position.y - body.positionPrev.y) * timeScale
7770        };
7771    };
7772
7773    /**
7774     * Gets the current linear speed of the body.  
7775     * Equivalent to the magnitude of its velocity.
7776     * @method getSpeed
7777     * @param {body} body
7778     * @return {number} speed
7779     */
7780    Body.getSpeed = function(body) {
7781        return Vector.magnitude(Body.getVelocity(body));
7782    };
7783
7784    /**
7785     * Sets the current linear speed of the body.  
7786     * Direction is maintained. Affects body velocity.
7787     * @method setSpeed
7788     * @param {body} body
7789     * @param {number} speed
7790     */
7791    Body.setSpeed = function(body, speed) {
7792        Body.setVelocity(body, Vector.mult(Vector.normalise(Body.getVelocity(body)), speed));
7793    };
7794
7795    /**
7796     * Sets the current rotational velocity of the body.  
7797     * Affects body angular speed.
7798     * @method setAngularVelocity
7799     * @param {body} body
7800     * @param {number} velocity
7801     */
7802    Body.setAngularVelocity = function(body, velocity) {
7803        var timeScale = body.deltaTime / Body._baseDelta;
7804        body.anglePrev = body.angle - velocity * timeScale;
7805        body.angularVelocity = (body.angle - body.anglePrev) / timeScale;
7806        body.angularSpeed = Math.abs(body.angularVelocity);
7807    };
7808
7809    /**
7810     * Gets the current rotational velocity of the body.
7811     * @method getAngularVelocity
7812     * @param {body} body
7813     * @return {number} angular velocity
7814     */
7815    Body.getAngularVelocity = function(body) {
7816        return (body.angle - body.anglePrev) * Body._baseDelta / body.deltaTime;
7817    };
7818
7819    /**
7820     * Gets the current rotational speed of the body.  
7821     * Equivalent to the magnitude of its angular velocity.
7822     * @method getAngularSpeed
7823     * @param {body} body
7824     * @return {number} angular speed
7825     */
7826    Body.getAngularSpeed = function(body) {
7827        return Math.abs(Body.getAngularVelocity(body));
7828    };
7829
7830    /**
7831     * Sets the current rotational speed of the body.  
7832     * Direction is maintained. Affects body angular velocity.
7833     * @method setAngularSpeed
7834     * @param {body} body
7835     * @param {number} speed
7836     */
7837    Body.setAngularSpeed = function(body, speed) {
7838        Body.setAngularVelocity(body, Common.sign(Body.getAngularVelocity(body)) * speed);
7839    };
7840
7841    /**
7842     * Moves a body by a given vector relative to its current position. By default velocity is unchanged.
7843     * If `updateVelocity` is `true` then velocity is inferred from the change in position.
7844     * @method translate
7845     * @param {body} body
7846     * @param {vector} translation
7847     * @param {boolean} [updateVelocity=false]
7848     */
7849    Body.translate = function(body, translation, updateVelocity) {
7850        Body.setPosition(body, Vector.add(body.position, translation), updateVelocity);
7851    };
7852
7853    /**
7854     * Rotates a body by a given angle relative to its current angle. By default angular velocity is unchanged.
7855     * If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.
7856     * @method rotate
7857     * @param {body} body
7858     * @param {number} rotation
7859     * @param {vector} [point]
7860     * @param {boolean} [updateVelocity=false]
7861     */
7862    Body.rotate = function(body, rotation, point, updateVelocity) {
7863        if (!point) {
7864            Body.setAngle(body, body.angle + rotation, updateVelocity);
7865        } else {
7866            var cos = Math.cos(rotation),
7867                sin = Math.sin(rotation),
7868                dx = body.position.x - point.x,
7869                dy = body.position.y - point.y;
7870                
7871            Body.setPosition(body, {
7872                x: point.x + (dx * cos - dy * sin),
7873                y: point.y + (dx * sin + dy * cos)
7874            }, updateVelocity);
7875
7876            Body.setAngle(body, body.angle + rotation, updateVelocity);
7877        }
7878    };
7879
7880    /**
7881     * Scales the body, including updating physical properties (mass, area, axes, inertia), from a world-space point (default is body centre).
7882     * @method scale
7883     * @param {body} body
7884     * @param {number} scaleX
7885     * @param {number} scaleY
7886     * @param {vector} [point]
7887     */
7888    Body.scale = function(body, scaleX, scaleY, point) {
7889        var totalArea = 0,
7890            totalInertia = 0;
7891
7892        point = point || body.position;
7893
7894        for (var i = 0; i < body.parts.length; i++) {
7895            var part = body.parts[i];
7896
7897            // scale vertices
7898            Vertices.scale(part.vertices, scaleX, scaleY, point);
7899
7900            // update properties
7901            part.axes = Axes.fromVertices(part.vertices);
7902            part.area = Vertices.area(part.vertices);
7903            Body.setMass(part, body.density * part.area);
7904
7905            // update inertia (requires vertices to be at origin)
7906            Vertices.translate(part.vertices, { x: -part.position.x, y: -part.position.y });
7907            Body.setInertia(part, Body._inertiaScale * Vertices.inertia(part.vertices, part.mass));
7908            Vertices.translate(part.vertices, { x: part.position.x, y: part.position.y });
7909
7910            if (i > 0) {
7911                totalArea += part.area;
7912                totalInertia += part.inertia;
7913            }
7914
7915            // scale position
7916            part.position.x = point.x + (part.position.x - point.x) * scaleX;
7917            part.position.y = point.y + (part.position.y - point.y) * scaleY;
7918
7919            // update bounds
7920            Bounds.update(part.bounds, part.vertices, body.velocity);
7921        }
7922
7923        // handle parent body
7924        if (body.parts.length > 1) {
7925            body.area = totalArea;
7926
7927            if (!body.isStatic) {
7928                Body.setMass(body, body.density * totalArea);
7929                Body.setInertia(body, totalInertia);
7930            }
7931        }
7932
7933        // handle circles
7934        if (body.circleRadius) { 
7935            if (scaleX === scaleY) {
7936                body.circleRadius *= scaleX;
7937            } else {
7938                // body is no longer a circle
7939                body.circleRadius = null;
7940            }
7941        }
7942    };
7943
7944    /**
7945     * Performs an update by integrating the equations of motion on the `body`.
7946     * This is applied every update by `Matter.Engine` automatically.
7947     * @method update
7948     * @param {body} body
7949     * @param {number} [deltaTime=16.666]
7950     */
7951    Body.update = function(body, deltaTime) {
7952        deltaTime = (typeof deltaTime !== 'undefined' ? deltaTime : (1000 / 60)) * body.timeScale;
7953
7954        var deltaTimeSquared = deltaTime * deltaTime,
7955            correction = Body._timeCorrection ? deltaTime / (body.deltaTime || deltaTime) : 1;
7956
7957        // from the previous step
7958        var frictionAir = 1 - body.frictionAir * (deltaTime / Common._baseDelta),
7959            velocityPrevX = (body.position.x - body.positionPrev.x) * correction,
7960            velocityPrevY = (body.position.y - body.positionPrev.y) * correction;
7961
7962        // update velocity with Verlet integration
7963        body.velocity.x = (velocityPrevX * frictionAir) + (body.force.x / body.mass) * deltaTimeSquared;
7964        body.velocity.y = (velocityPrevY * frictionAir) + (body.force.y / body.mass) * deltaTimeSquared;
7965
7966        body.positionPrev.x = body.position.x;
7967        body.positionPrev.y = body.position.y;
7968        body.position.x += body.velocity.x;
7969        body.position.y += body.velocity.y;
7970        body.deltaTime = deltaTime;
7971
7972        // update angular velocity with Verlet integration
7973        body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared;
7974        body.anglePrev = body.angle;
7975        body.angle += body.angularVelocity;
7976
7977        // transform the body geometry
7978        for (var i = 0; i < body.parts.length; i++) {
7979            var part = body.parts[i];
7980
7981            Vertices.translate(part.vertices, body.velocity);
7982            
7983            if (i > 0) {
7984                part.position.x += body.velocity.x;
7985                part.position.y += body.velocity.y;
7986            }
7987
7988            if (body.angularVelocity !== 0) {
7989                Vertices.rotate(part.vertices, body.angularVelocity, body.position);
7990                Axes.rotate(part.axes, body.angularVelocity);
7991                if (i > 0) {
7992                    Vector.rotateAbout(part.position, body.angularVelocity, body.position, part.position);
7993                }
7994            }
7995
7996            Bounds.update(part.bounds, part.vertices, body.velocity);
7997        }
7998    };
7999
8000    /**
8001     * Updates properties `body.velocity`, `body.speed`, `body.angularVelocity` and `body.angularSpeed` which are normalised in relation to `Body._baseDelta`.
8002     * @method updateVelocities
8003     * @param {body} body
8004     */
8005    Body.updateVelocities = function(body) {
8006        var timeScale = Body._baseDelta / body.deltaTime,
8007            bodyVelocity = body.velocity;
8008
8009        bodyVelocity.x = (body.position.x - body.positionPrev.x) * timeScale;
8010        bodyVelocity.y = (body.position.y - body.positionPrev.y) * timeScale;
8011        body.speed = Math.sqrt((bodyVelocity.x * bodyVelocity.x) + (bodyVelocity.y * bodyVelocity.y));
8012
8013        body.angularVelocity = (body.angle - body.anglePrev) * timeScale;
8014        body.angularSpeed = Math.abs(body.angularVelocity);
8015    };
8016
8017    /**
8018     * Applies the `force` to the `body` from the force origin `position` in world-space, over a single timestep, including applying any resulting angular torque.
8019     * 
8020     * Forces are useful for effects like gravity, wind or rocket thrust, but can be difficult in practice when precise control is needed. In these cases see `Body.setVelocity` and `Body.setPosition` as an alternative.
8021     * 
8022     * The force from this function is only applied once for the duration of a single timestep, in other words the duration depends directly on the current engine update `delta` and the rate of calls to this function.
8023     * 
8024     * Therefore to account for time, you should apply the force constantly over as many engine updates as equivalent to the intended duration.
8025     * 
8026     * If all or part of the force duration is some fraction of a timestep, first multiply the force by `duration / timestep`.
8027     * 
8028     * The force origin `position` in world-space must also be specified. Passing `body.position` will result in zero angular effect as the force origin would be at the centre of mass.
8029     * 
8030     * The `body` will take time to accelerate under a force, the resulting effect depends on duration of the force, the body mass and other forces on the body including friction combined.
8031     * @method applyForce
8032     * @param {body} body
8033     * @param {vector} position The force origin in world-space. Pass `body.position` to avoid angular torque.
8034     * @param {vector} force
8035     */
8036    Body.applyForce = function(body, position, force) {
8037        var offset = { x: position.x - body.position.x, y: position.y - body.position.y };
8038        body.force.x += force.x;
8039        body.force.y += force.y;
8040        body.torque += offset.x * force.y - offset.y * force.x;
8041    };
8042
8043    /**
8044     * Returns the sums of the properties of all compound parts of the parent body.
8045     * @method _totalProperties
8046     * @private
8047     * @param {body} body
8048     * @return {}
8049     */
8050    Body._totalProperties = function(body) {
8051        // from equations at:
8052        // https://ecourses.ou.edu/cgi-bin/ebook.cgi?doc=&topic=st&chap_sec=07.2&page=theory
8053        // http://output.to/sideway/default.asp?qno=121100087
8054
8055        var properties = {
8056            mass: 0,
8057            area: 0,
8058            inertia: 0,
8059            centre: { x: 0, y: 0 }
8060        };
8061
8062        // sum the properties of all compound parts of the parent body
8063        for (var i = body.parts.length === 1 ? 0 : 1; i < body.parts.length; i++) {
8064            var part = body.parts[i],
8065                mass = part.mass !== Infinity ? part.mass : 1;
8066
8067            properties.mass += mass;
8068            properties.area += part.area;
8069            properties.inertia += part.inertia;
8070            properties.centre = Vector.add(properties.centre, Vector.mult(part.position, mass));
8071        }
8072
8073        properties.centre = Vector.div(properties.centre, properties.mass);
8074
8075        return properties;
8076    };
8077
8078    /*
8079    *
8080    *  Events Documentation
8081    *
8082    */
8083
8084    /**
8085    * Fired when a body starts sleeping (where `this` is the body).
8086    *
8087    * @event sleepStart
8088    * @this {body} The body that has started sleeping
8089    * @param {} event An event object
8090    * @param {} event.source The source object of the event
8091    * @param {} event.name The name of the event
8092    */
8093
8094    /**
8095    * Fired when a body ends sleeping (where `this` is the body).
8096    *
8097    * @event sleepEnd
8098    * @this {body} The body that has ended sleeping
8099    * @param {} event An event object
8100    * @param {} event.source The source object of the event
8101    * @param {} event.name The name of the event
8102    */
8103
8104    /*
8105    *
8106    *  Properties Documentation
8107    *
8108    */
8109
8110    /**
8111     * An integer `Number` uniquely identifying number generated in `Body.create` by `Common.nextId`.
8112     *
8113     * @property id
8114     * @type number
8115     */
8116
8117    /**
8118     * _Read only_. Set by `Body.create`.
8119     * 
8120     * A `String` denoting the type of object.
8121     *
8122     * @readOnly
8123     * @property type
8124     * @type string
8125     * @default "body"
8126     */
8127
8128    /**
8129     * An arbitrary `String` name to help the user identify and manage bodies.
8130     *
8131     * @property label
8132     * @type string
8133     * @default "Body"
8134     */
8135
8136    /**
8137     * _Read only_. Use `Body.setParts` to set. 
8138     * 
8139     * See `Bodies.fromVertices` for a related utility.
8140     * 
8141     * An array of bodies (the 'parts') that make up this body (the 'parent'). The first body in this array must always be a self-reference to this `body`.  
8142     * 
8143     * The parts are fixed together and therefore perform as a single unified rigid body.
8144     * 
8145     * Parts in relation to each other are allowed to overlap, as well as form gaps or holes, so can be used to create complex concave bodies unlike when using a single part. 
8146     * 
8147     * Use properties and functions on the parent `body` rather than on parts.
8148     *   
8149     * Outside of their geometry, most properties on parts are not considered or updated.  
8150     * As such 'per-part' material properties among others are not currently considered.
8151     * 
8152     * Parts should be created specifically for their parent body.  
8153     * Parts should not be shared or reused between bodies, only one parent is supported.  
8154     * Parts should not have their own parts, they are not handled recursively.  
8155     * Parts should not be added to the world directly or any other composite.  
8156     * Parts own vertices must be convex and in clockwise order.   
8157     * 
8158     * A body with more than one part is sometimes referred to as a 'compound' body. 
8159     * 
8160     * Use `Body.setParts` when setting parts to ensure correct updates of all properties.  
8161     *
8162     * @readOnly
8163     * @property parts
8164     * @type body[]
8165     */
8166
8167    /**
8168     * An object reserved for storing plugin-specific properties.
8169     *
8170     * @property plugin
8171     * @type {}
8172     */
8173
8174    /**
8175     * _Read only_. Updated by `Body.setParts`.
8176     * 
8177     * A reference to the body that this is a part of. See `body.parts`.
8178     * This is a self reference if the body is not a part of another body.
8179     *
8180     * @readOnly
8181     * @property parent
8182     * @type body
8183     */
8184
8185    /**
8186     * A `Number` specifying the angle of the body, in radians.
8187     *
8188     * @property angle
8189     * @type number
8190     * @default 0
8191     */
8192
8193    /**
8194     * _Read only_. Use `Body.setVertices` or `Body.setParts` to set. See also `Bodies.fromVertices`.
8195     * 
8196     * An array of `Vector` objects that specify the convex hull of the rigid body.
8197     * These should be provided about the origin `(0, 0)`. E.g.
8198     *
8199     * `[{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }]`
8200     * 
8201     * Vertices must always be convex, in clockwise order and must not contain any duplicate points.
8202     * 
8203     * Concave vertices should be decomposed into convex `parts`, see `Bodies.fromVertices` and `Body.setParts`.
8204     *
8205     * When set the vertices are translated such that `body.position` is at the centre of mass.
8206     * Many other body properties are automatically calculated from these vertices when set including `density`, `area` and `inertia`.
8207     * 
8208     * The module `Matter.Vertices` contains useful methods for working with vertices.
8209     *
8210     * @readOnly
8211     * @property vertices
8212     * @type vector[]
8213     */
8214
8215    /**
8216     * _Read only_. Use `Body.setPosition` to set. 
8217     * 
8218     * A `Vector` that specifies the current world-space position of the body.
8219     * 
8220     * @readOnly
8221     * @property position
8222     * @type vector
8223     * @default { x: 0, y: 0 }
8224     */
8225
8226    /**
8227     * A `Vector` that accumulates the total force applied to the body for a single update.
8228     * Force is zeroed after every `Engine.update`, so constant forces should be applied for every update they are needed. See also `Body.applyForce`.
8229     * 
8230     * @property force
8231     * @type vector
8232     * @default { x: 0, y: 0 }
8233     */
8234
8235    /**
8236     * A `Number` that accumulates the total torque (turning force) applied to the body for a single update. See also `Body.applyForce`.
8237     * Torque is zeroed after every `Engine.update`, so constant torques should be applied for every update they are needed.
8238     *
8239     * Torques result in angular acceleration on every update, which depends on body inertia and the engine update delta.
8240     * 
8241     * @property torque
8242     * @type number
8243     * @default 0
8244     */
8245
8246    /**
8247     * _Read only_. Use `Body.setSpeed` to set. 
8248     * 
8249     * See `Body.getSpeed` for details.
8250     * 
8251     * Equivalent to the magnitude of `body.velocity` (always positive).
8252     * 
8253     * @readOnly
8254     * @property speed
8255     * @type number
8256     * @default 0
8257     */
8258
8259    /**
8260     * _Read only_. Use `Body.setVelocity` to set. 
8261     * 
8262     * See `Body.getVelocity` for details.
8263     * 
8264     * Equivalent to the magnitude of `body.angularVelocity` (always positive).
8265     * 
8266     * @readOnly
8267     * @property velocity
8268     * @type vector
8269     * @default { x: 0, y: 0 }
8270     */
8271
8272    /**
8273     * _Read only_. Use `Body.setAngularSpeed` to set. 
8274     * 
8275     * See `Body.getAngularSpeed` for details.
8276     * 
8277     * 
8278     * @readOnly
8279     * @property angularSpeed
8280     * @type number
8281     * @default 0
8282     */
8283
8284    /**
8285     * _Read only_. Use `Body.setAngularVelocity` to set. 
8286     * 
8287     * See `Body.getAngularVelocity` for details.
8288     * 
8289     *
8290     * @readOnly
8291     * @property angularVelocity
8292     * @type number
8293     * @default 0
8294     */
8295
8296    /**
8297     * _Read only_. Use `Body.setStatic` to set. 
8298     * 
8299     * A flag that indicates whether a body is considered static. A static body can never change position or angle and is completely fixed.
8300     *
8301     * @readOnly
8302     * @property isStatic
8303     * @type boolean
8304     * @default false
8305     */
8306
8307    /**
8308     * A flag that indicates whether a body is a sensor. Sensor triggers collision events, but doesn't react with colliding body physically.
8309     *
8310     * @property isSensor
8311     * @type boolean
8312     * @default false
8313     */
8314
8315    /**
8316     * _Read only_. Use `Sleeping.set` to set. 
8317     * 
8318     * A flag that indicates whether the body is considered sleeping. A sleeping body acts similar to a static body, except it is only temporary and can be awoken.
8319     *
8320     * @readOnly
8321     * @property isSleeping
8322     * @type boolean
8323     * @default false
8324     */
8325
8326    /**
8327     * _Read only_. Calculated during engine update only when sleeping is enabled.
8328     * 
8329     * A `Number` that loosely measures the amount of movement a body currently has.
8330     *
8331     * Derived from `body.speed^2 + body.angularSpeed^2`. See `Sleeping.update`.
8332     * 
8333     * @readOnly
8334     * @property motion
8335     * @type number
8336     * @default 0
8337     */
8338
8339    /**
8340     * A `Number` that defines the length of time during which this body must have near-zero velocity before it is set as sleeping by the `Matter.Sleeping` module (if sleeping is enabled by the engine).
8341     * 
8342     * @property sleepThreshold
8343     * @type number
8344     * @default 60
8345     */
8346
8347    /**
8348     * _Read only_. Use `Body.setDensity` to set. 
8349     * 
8350     * A `Number` that defines the density of the body (mass per unit area).
8351     * 
8352     * Mass will also be updated when set.
8353     *
8354     * @readOnly
8355     * @property density
8356     * @type number
8357     * @default 0.001
8358     */
8359
8360    /**
8361     * _Read only_. Use `Body.setMass` to set. 
8362     * 
8363     * A `Number` that defines the mass of the body.
8364     * 
8365     * Density will also be updated when set.
8366     * 
8367     * @readOnly
8368     * @property mass
8369     * @type number
8370     */
8371
8372    /**
8373     * _Read only_. Use `Body.setMass` to set. 
8374     * 
8375     * A `Number` that defines the inverse mass of the body (`1 / mass`).
8376     *
8377     * @readOnly
8378     * @property inverseMass
8379     * @type number
8380     */
8381
8382    /**
8383     * _Read only_. Automatically calculated when vertices, mass or density are set or set through `Body.setInertia`.
8384     * 
8385     * A `Number` that defines the moment of inertia of the body. This is the second moment of area in two dimensions.
8386     * 
8387     * Can be manually set to `Infinity` to prevent rotation of the body. See `Body.setInertia`.
8388     * 
8389     * @readOnly
8390     * @property inertia
8391     * @type number
8392     */
8393
8394    /**
8395     * _Read only_. Automatically calculated when vertices, mass or density are set or calculated by `Body.setInertia`.
8396     * 
8397     * A `Number` that defines the inverse moment of inertia of the body (`1 / inertia`).
8398     * 
8399     * @readOnly
8400     * @property inverseInertia
8401     * @type number
8402     */
8403
8404    /**
8405     * A `Number` that defines the restitution (elasticity) of the body. The value is always positive and is in the range `(0, 1)`.
8406     * A value of `0` means collisions may be perfectly inelastic and no bouncing may occur. 
8407     * A value of `0.8` means the body may bounce back with approximately 80% of its kinetic energy.
8408     * Note that collision response is based on _pairs_ of bodies, and that `restitution` values are _combined_ with the following formula:
8409     *
8410     * `Math.max(bodyA.restitution, bodyB.restitution)`
8411     *
8412     * @property restitution
8413     * @type number
8414     * @default 0
8415     */
8416
8417    /**
8418     * A `Number` that defines the friction of the body. The value is always positive and is in the range `(0, 1)`.
8419     * A value of `0` means that the body may slide indefinitely.
8420     * A value of `1` means the body may come to a stop almost instantly after a force is applied.
8421     *
8422     * The effects of the value may be non-linear. 
8423     * High values may be unstable depending on the body.
8424     * The engine uses a Coulomb friction model including static and kinetic friction.
8425     * Note that collision response is based on _pairs_ of bodies, and that `friction` values are _combined_ with the following formula:
8426     *
8427     * `Math.min(bodyA.friction, bodyB.friction)`
8428     *
8429     * @property friction
8430     * @type number
8431     * @default 0.1
8432     */
8433
8434    /**
8435     * A `Number` that defines the static friction of the body (in the Coulomb friction model). 
8436     * A value of `0` means the body will never 'stick' when it is nearly stationary and only dynamic `friction` is used.
8437     * The higher the value (e.g. `10`), the more force it will take to initially get the body moving when nearly stationary.
8438     * This value is multiplied with the `friction` property to make it easier to change `friction` and maintain an appropriate amount of static friction.
8439     *
8440     * @property frictionStatic
8441     * @type number
8442     * @default 0.5
8443     */
8444
8445    /**
8446     * A `Number` that defines the air friction of the body (air resistance). 
8447     * A value of `0` means the body will never slow as it moves through space.
8448     * The higher the value, the faster a body slows when moving through space.
8449     * The effects of the value are non-linear. 
8450     *
8451     * @property frictionAir
8452     * @type number
8453     * @default 0.01
8454     */
8455
8456    /**
8457     * An `Object` that specifies the collision filtering properties of this body.
8458     *
8459     * Collisions between two bodies will obey the following rules:
8460     * - If the two bodies have the same non-zero value of `collisionFilter.group`,
8461     *   they will always collide if the value is positive, and they will never collide
8462     *   if the value is negative.
8463     * - If the two bodies have different values of `collisionFilter.group` or if one
8464     *   (or both) of the bodies has a value of 0, then the category/mask rules apply as follows:
8465     *
8466     * Each body belongs to a collision category, given by `collisionFilter.category`. This
8467     * value is used as a bit field and the category should have only one bit set, meaning that
8468     * the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32
8469     * different collision categories available.
8470     *
8471     * Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies
8472     * the categories it collides with (the value is the bitwise AND value of all these categories).
8473     *
8474     * Using the category/mask rules, two bodies `A` and `B` collide if each includes the other's
8475     * category in its mask, i.e. `(categoryA & maskB) !== 0` and `(categoryB & maskA) !== 0`
8476     * are both true.
8477     *
8478     * @property collisionFilter
8479     * @type object
8480     */
8481
8482    /**
8483     * An Integer `Number`, that specifies the collision group this body belongs to.
8484     * See `body.collisionFilter` for more information.
8485     *
8486     * @property collisionFilter.group
8487     * @type object
8488     * @default 0
8489     */
8490
8491    /**
8492     * A bit field that specifies the collision category this body belongs to.
8493     * The category value should have only one bit set, for example `0x0001`.
8494     * This means there are up to 32 unique collision categories available.
8495     * See `body.collisionFilter` for more information.
8496     *
8497     * @property collisionFilter.category
8498     * @type object
8499     * @default 1
8500     */
8501
8502    /**
8503     * A bit mask that specifies the collision categories this body may collide with.
8504     * See `body.collisionFilter` for more information.
8505     *
8506     * @property collisionFilter.mask
8507     * @type object
8508     * @default -1
8509     */
8510
8511    /**
8512     * A `Number` that specifies a thin boundary around the body where it is allowed to slightly sink into other bodies.
8513     * 
8514     * This is required for proper collision response, including friction and restitution effects.
8515     * 
8516     * The default should generally suffice in most cases. You may need to decrease this value for very small bodies that are nearing the default value in scale.
8517     *
8518     * @property slop
8519     * @type number
8520     * @default 0.05
8521     */
8522
8523    /**
8524     * A `Number` that specifies per-body time scaling.
8525     *
8526     * @property timeScale
8527     * @type number
8528     * @default 1
8529     */
8530
8531    /**
8532     * _Read only_. Updated during engine update.
8533     * 
8534     * A `Number` that records the last delta time value used to update this body.
8535     * Used to calculate speed and velocity.
8536     *
8537     * @readOnly
8538     * @property deltaTime
8539     * @type number
8540     * @default 1000 / 60
8541     */
8542
8543    /**
8544     * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`.
8545     *
8546     * @property render
8547     * @type object
8548     */
8549
8550    /**
8551     * A flag that indicates if the body should be rendered.
8552     *
8553     * @property render.visible
8554     * @type boolean
8555     * @default true
8556     */
8557
8558    /**
8559     * Sets the opacity to use when rendering.
8560     *
8561     * @property render.opacity
8562     * @type number
8563     * @default 1
8564    */
8565
8566    /**
8567     * An `Object` that defines the sprite properties to use when rendering, if any.
8568     *
8569     * @property render.sprite
8570     * @type object
8571     */
8572
8573    /**
8574     * An `String` that defines the path to the image to use as the sprite texture, if any.
8575     *
8576     * @property render.sprite.texture
8577     * @type string
8578     */
8579     
8580    /**
8581     * A `Number` that defines the scaling in the x-axis for the sprite, if any.
8582     *
8583     * @property render.sprite.xScale
8584     * @type number
8585     * @default 1
8586     */
8587
8588    /**
8589     * A `Number` that defines the scaling in the y-axis for the sprite, if any.
8590     *
8591     * @property render.sprite.yScale
8592     * @type number
8593     * @default 1
8594     */
8595
8596    /**
8597      * A `Number` that defines the offset in the x-axis for the sprite (normalised by texture width).
8598      *
8599      * @property render.sprite.xOffset
8600      * @type number
8601      * @default 0
8602      */
8603
8604    /**
8605      * A `Number` that defines the offset in the y-axis for the sprite (normalised by texture height).
8606      *
8607      * @property render.sprite.yOffset
8608      * @type number
8609      * @default 0
8610      */
8611
8612    /**
8613     * A `Number` that defines the line width to use when rendering the body outline (if a sprite is not defined).
8614     * A value of `0` means no outline will be rendered.
8615     *
8616     * @property render.lineWidth
8617     * @type number
8618     * @default 0
8619     */
8620
8621    /**
8622     * A `String` that defines the fill style to use when rendering the body (if a sprite is not defined).
8623     * It is the same as when using a canvas, so it accepts CSS style property values.
8624     *
8625     * @property render.fillStyle
8626     * @type string
8627     * @default a random colour
8628     */
8629
8630    /**
8631     * A `String` that defines the stroke style to use when rendering the body outline (if a sprite is not defined).
8632     * It is the same as when using a canvas, so it accepts CSS style property values.
8633     *
8634     * @property render.strokeStyle
8635     * @type string
8636     * @default a random colour
8637     */
8638
8639    /**
8640     * _Read only_. Calculated automatically when vertices are set.
8641     * 
8642     * An array of unique axis vectors (edge normals) used for collision detection.
8643     * These are automatically calculated when vertices are set.
8644     * They are constantly updated by `Body.update` during the simulation.
8645     *
8646     * @readOnly
8647     * @property axes
8648     * @type vector[]
8649     */
8650     
8651    /**
8652     * _Read only_. Calculated automatically when vertices are set.
8653     * 
8654     * A `Number` that measures the area of the body's convex hull.
8655     * 
8656     * @readOnly
8657     * @property area
8658     * @type string
8659     * @default 
8660     */
8661
8662    /**
8663     * A `Bounds` object that defines the AABB region for the body.
8664     * It is automatically calculated when vertices are set and constantly updated by `Body.update` during simulation.
8665     * 
8666     * @property bounds
8667     * @type bounds
8668     */
8669
8670    /**
8671     * Temporarily may hold parameters to be passed to `Vertices.chamfer` where supported by external functions.
8672     * 
8673     * See `Vertices.chamfer` for possible parameters this object may hold.
8674     * 
8675     * Currently only functions inside `Matter.Bodies` provide a utility using this property as a vertices pre-processing option.
8676     * 
8677     * Alternatively consider using `Vertices.chamfer` directly on vertices before passing them to a body creation function.
8678     * 
8679     * @property chamfer
8680     * @type object|null|undefined
8681     */
8682
8683})();
8684
8685
8686/***/ }),
8687/* 5 */
8688/***/ (function(module, exports, __webpack_require__) {
8689
8690/**
8691* The `Matter.Events` module contains methods to fire and listen to events on other objects.
8692*
8693* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
8694*
8695* @class Events
8696*/
8697
8698var Events = {};
8699
8700module.exports = Events;
8701
8702var Common = __webpack_require__(0);
8703
8704(function() {
8705
8706    /**
8707     * Subscribes a callback function to the given object's `eventName`.
8708     * @method on
8709     * @param {} object
8710     * @param {string} eventNames
8711     * @param {function} callback
8712     */
8713    Events.on = function(object, eventNames, callback) {
8714        var names = eventNames.split(' '),
8715            name;
8716
8717        for (var i = 0; i < names.length; i++) {
8718            name = names[i];
8719            object.events = object.events || {};
8720            object.events[name] = object.events[name] || [];
8721            object.events[name].push(callback);
8722        }
8723
8724        return callback;
8725    };
8726
8727    /**
8728     * Removes the given event callback. If no callback, clears all callbacks in `eventNames`. If no `eventNames`, clears all events.
8729     * @method off
8730     * @param {} object
8731     * @param {string} eventNames
8732     * @param {function} callback
8733     */
8734    Events.off = function(object, eventNames, callback) {
8735        if (!eventNames) {
8736            object.events = {};
8737            return;
8738        }
8739
8740        // handle Events.off(object, callback)
8741        if (typeof eventNames === 'function') {
8742            callback = eventNames;
8743            eventNames = Common.keys(object.events).join(' ');
8744        }
8745
8746        var names = eventNames.split(' ');
8747
8748        for (var i = 0; i < names.length; i++) {
8749            var callbacks = object.events[names[i]],
8750                newCallbacks = [];
8751
8752            if (callback && callbacks) {
8753                for (var j = 0; j < callbacks.length; j++) {
8754                    if (callbacks[j] !== callback)
8755                        newCallbacks.push(callbacks[j]);
8756                }
8757            }
8758
8759            object.events[names[i]] = newCallbacks;
8760        }
8761    };
8762
8763    /**
8764     * Fires all the callbacks subscribed to the given object's `eventName`, in the order they subscribed, if any.
8765     * @method trigger
8766     * @param {} object
8767     * @param {string} eventNames
8768     * @param {} event
8769     */
8770    Events.trigger = function(object, eventNames, event) {
8771        var names,
8772            name,
8773            callbacks,
8774            eventClone;
8775
8776        var events = object.events;
8777        
8778        if (events && Common.keys(events).length > 0) {
8779            if (!event)
8780                event = {};
8781
8782            names = eventNames.split(' ');
8783
8784            for (var i = 0; i < names.length; i++) {
8785                name = names[i];
8786                callbacks = events[name];
8787
8788                if (callbacks) {
8789                    eventClone = Common.clone(event, false);
8790                    eventClone.name = name;
8791                    eventClone.source = object;
8792
8793                    for (var j = 0; j < callbacks.length; j++) {
8794                        callbacks[j].apply(object, [eventClone]);
8795                    }
8796                }
8797            }
8798        }
8799    };
8800
8801})();
8802
8803
8804/***/ }),
8805/* 6 */
8806/***/ (function(module, exports, __webpack_require__) {
8807
8808/**
8809* A composite is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite` objects.
8810*
8811* They are a container that can represent complex objects made of multiple parts, even if they are not physically connected.
8812* A composite could contain anything from a single body all the way up to a whole world.
8813* 
8814* When making any changes to composites, use the included functions rather than changing their properties directly.
8815*
8816* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
8817*
8818* @class Composite
8819*/
8820
8821var Composite = {};
8822
8823module.exports = Composite;
8824
8825var Events = __webpack_require__(5);
8826var Common = __webpack_require__(0);
8827var Bounds = __webpack_require__(1);
8828var Body = __webpack_require__(4);
8829
8830(function() {
8831
8832    /**
8833     * Creates a new composite. The options parameter is an object that specifies any properties you wish to override the defaults.
8834     * See the properites section below for detailed information on what you can pass via the `options` object.
8835     * @method create
8836     * @param {} [options]
8837     * @return {composite} A new composite
8838     */
8839    Composite.create = function(options) {
8840        return Common.extend({ 
8841            id: Common.nextId(),
8842            type: 'composite',
8843            parent: null,
8844            isModified: false,
8845            bodies: [], 
8846            constraints: [], 
8847            composites: [],
8848            label: 'Composite',
8849            plugin: {},
8850            cache: {
8851                allBodies: null,
8852                allConstraints: null,
8853                allComposites: null
8854            }
8855        }, options);
8856    };
8857
8858    /**
8859     * Sets the composite's `isModified` flag. 
8860     * If `updateParents` is true, all parents will be set (default: false).
8861     * If `updateChildren` is true, all children will be set (default: false).
8862     * @private
8863     * @method setModified
8864     * @param {composite} composite
8865     * @param {boolean} isModified
8866     * @param {boolean} [updateParents=false]
8867     * @param {boolean} [updateChildren=false]
8868     */
8869    Composite.setModified = function(composite, isModified, updateParents, updateChildren) {
8870        composite.isModified = isModified;
8871
8872        if (isModified && composite.cache) {
8873            composite.cache.allBodies = null;
8874            composite.cache.allConstraints = null;
8875            composite.cache.allComposites = null;
8876        }
8877
8878        if (updateParents && composite.parent) {
8879            Composite.setModified(composite.parent, isModified, updateParents, updateChildren);
8880        }
8881
8882        if (updateChildren) {
8883            for (var i = 0; i < composite.composites.length; i++) {
8884                var childComposite = composite.composites[i];
8885                Composite.setModified(childComposite, isModified, updateParents, updateChildren);
8886            }
8887        }
8888    };
8889
8890    /**
8891     * Generic single or multi-add function. Adds a single or an array of body(s), constraint(s) or composite(s) to the given composite.
8892     * Triggers `beforeAdd` and `afterAdd` events on the `composite`.
8893     * @method add
8894     * @param {composite} composite
8895     * @param {object|array} object A single or an array of body(s), constraint(s) or composite(s)
8896     * @return {composite} The original composite with the objects added
8897     */
8898    Composite.add = function(composite, object) {
8899        var objects = [].concat(object);
8900
8901        Events.trigger(composite, 'beforeAdd', { object: object });
8902
8903        for (var i = 0; i < objects.length; i++) {
8904            var obj = objects[i];
8905
8906            switch (obj.type) {
8907
8908            case 'body':
8909                // skip adding compound parts
8910                if (obj.parent !== obj) {
8911                    Common.warn('Composite.add: skipped adding a compound body part (you must add its parent instead)');
8912                    break;
8913                }
8914
8915                Composite.addBody(composite, obj);
8916                break;
8917            case 'constraint':
8918                Composite.addConstraint(composite, obj);
8919                break;
8920            case 'composite':
8921                Composite.addComposite(composite, obj);
8922                break;
8923            case 'mouseConstraint':
8924                Composite.addConstraint(composite, obj.constraint);
8925                break;
8926
8927            }
8928        }
8929
8930        Events.trigger(composite, 'afterAdd', { object: object });
8931
8932        return composite;
8933    };
8934
8935    /**
8936     * Generic remove function. Removes one or many body(s), constraint(s) or a composite(s) to the given composite.
8937     * Optionally searching its children recursively.
8938     * Triggers `beforeRemove` and `afterRemove` events on the `composite`.
8939     * @method remove
8940     * @param {composite} composite
8941     * @param {object|array} object
8942     * @param {boolean} [deep=false]
8943     * @return {composite} The original composite with the objects removed
8944     */
8945    Composite.remove = function(composite, object, deep) {
8946        var objects = [].concat(object);
8947
8948        Events.trigger(composite, 'beforeRemove', { object: object });
8949
8950        for (var i = 0; i < objects.length; i++) {
8951            var obj = objects[i];
8952
8953            switch (obj.type) {
8954
8955            case 'body':
8956                Composite.removeBody(composite, obj, deep);
8957                break;
8958            case 'constraint':
8959                Composite.removeConstraint(composite, obj, deep);
8960                break;
8961            case 'composite':
8962                Composite.removeComposite(composite, obj, deep);
8963                break;
8964            case 'mouseConstraint':
8965                Composite.removeConstraint(composite, obj.constraint);
8966                break;
8967
8968            }
8969        }
8970
8971        Events.trigger(composite, 'afterRemove', { object: object });
8972
8973        return composite;
8974    };
8975
8976    /**
8977     * Adds a composite to the given composite.
8978     * @private
8979     * @method addComposite
8980     * @param {composite} compositeA
8981     * @param {composite} compositeB
8982     * @return {composite} The original compositeA with the objects from compositeB added
8983     */
8984    Composite.addComposite = function(compositeA, compositeB) {
8985        compositeA.composites.push(compositeB);
8986        compositeB.parent = compositeA;
8987        Composite.setModified(compositeA, true, true, false);
8988        return compositeA;
8989    };
8990
8991    /**
8992     * Removes a composite from the given composite, and optionally searching its children recursively.
8993     * @private
8994     * @method removeComposite
8995     * @param {composite} compositeA
8996     * @param {composite} compositeB
8997     * @param {boolean} [deep=false]
8998     * @return {composite} The original compositeA with the composite removed
8999     */
9000    Composite.removeComposite = function(compositeA, compositeB, deep) {
9001        var position = Common.indexOf(compositeA.composites, compositeB);
9002
9003        if (position !== -1) {
9004            var bodies = Composite.allBodies(compositeB);
9005
9006            Composite.removeCompositeAt(compositeA, position);
9007
9008            for (var i = 0; i < bodies.length; i++) {
9009                bodies[i].sleepCounter = 0;
9010            }
9011        }
9012
9013        if (deep) {
9014            for (var i = 0; i < compositeA.composites.length; i++){
9015                Composite.removeComposite(compositeA.composites[i], compositeB, true);
9016            }
9017        }
9018
9019        return compositeA;
9020    };
9021
9022    /**
9023     * Removes a composite from the given composite.
9024     * @private
9025     * @method removeCompositeAt
9026     * @param {composite} composite
9027     * @param {number} position
9028     * @return {composite} The original composite with the composite removed
9029     */
9030    Composite.removeCompositeAt = function(composite, position) {
9031        composite.composites.splice(position, 1);
9032        Composite.setModified(composite, true, true, false);
9033        return composite;
9034    };
9035
9036    /**
9037     * Adds a body to the given composite.
9038     * @private
9039     * @method addBody
9040     * @param {composite} composite
9041     * @param {body} body
9042     * @return {composite} The original composite with the body added
9043     */
9044    Composite.addBody = function(composite, body) {
9045        composite.bodies.push(body);
9046        Composite.setModified(composite, true, true, false);
9047        return composite;
9048    };
9049
9050    /**
9051     * Removes a body from the given composite, and optionally searching its children recursively.
9052     * @private
9053     * @method removeBody
9054     * @param {composite} composite
9055     * @param {body} body
9056     * @param {boolean} [deep=false]
9057     * @return {composite} The original composite with the body removed
9058     */
9059    Composite.removeBody = function(composite, body, deep) {
9060        var position = Common.indexOf(composite.bodies, body);
9061
9062        if (position !== -1) {
9063            Composite.removeBodyAt(composite, position);
9064            body.sleepCounter = 0;
9065        }
9066
9067        if (deep) {
9068            for (var i = 0; i < composite.composites.length; i++){
9069                Composite.removeBody(composite.composites[i], body, true);
9070            }
9071        }
9072
9073        return composite;
9074    };
9075
9076    /**
9077     * Removes a body from the given composite.
9078     * @private
9079     * @method removeBodyAt
9080     * @param {composite} composite
9081     * @param {number} position
9082     * @return {composite} The original composite with the body removed
9083     */
9084    Composite.removeBodyAt = function(composite, position) {
9085        composite.bodies.splice(position, 1);
9086        Composite.setModified(composite, true, true, false);
9087        return composite;
9088    };
9089
9090    /**
9091     * Adds a constraint to the given composite.
9092     * @private
9093     * @method addConstraint
9094     * @param {composite} composite
9095     * @param {constraint} constraint
9096     * @return {composite} The original composite with the constraint added
9097     */
9098    Composite.addConstraint = function(composite, constraint) {
9099        composite.constraints.push(constraint);
9100        Composite.setModified(composite, true, true, false);
9101        return composite;
9102    };
9103
9104    /**
9105     * Removes a constraint from the given composite, and optionally searching its children recursively.
9106     * @private
9107     * @method removeConstraint
9108     * @param {composite} composite
9109     * @param {constraint} constraint
9110     * @param {boolean} [deep=false]
9111     * @return {composite} The original composite with the constraint removed
9112     */
9113    Composite.removeConstraint = function(composite, constraint, deep) {
9114        var position = Common.indexOf(composite.constraints, constraint);
9115        
9116        if (position !== -1) {
9117            Composite.removeConstraintAt(composite, position);
9118        }
9119
9120        if (deep) {
9121            for (var i = 0; i < composite.composites.length; i++){
9122                Composite.removeConstraint(composite.composites[i], constraint, true);
9123            }
9124        }
9125
9126        return composite;
9127    };
9128
9129    /**
9130     * Removes a body from the given composite.
9131     * @private
9132     * @method removeConstraintAt
9133     * @param {composite} composite
9134     * @param {number} position
9135     * @return {composite} The original composite with the constraint removed
9136     */
9137    Composite.removeConstraintAt = function(composite, position) {
9138        composite.constraints.splice(position, 1);
9139        Composite.setModified(composite, true, true, false);
9140        return composite;
9141    };
9142
9143    /**
9144     * Removes all bodies, constraints and composites from the given composite.
9145     * Optionally clearing its children recursively.
9146     * @method clear
9147     * @param {composite} composite
9148     * @param {boolean} keepStatic
9149     * @param {boolean} [deep=false]
9150     */
9151    Composite.clear = function(composite, keepStatic, deep) {
9152        if (deep) {
9153            for (var i = 0; i < composite.composites.length; i++){
9154                Composite.clear(composite.composites[i], keepStatic, true);
9155            }
9156        }
9157        
9158        if (keepStatic) {
9159            composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; });
9160        } else {
9161            composite.bodies.length = 0;
9162        }
9163
9164        composite.constraints.length = 0;
9165        composite.composites.length = 0;
9166
9167        Composite.setModified(composite, true, true, false);
9168
9169        return composite;
9170    };
9171
9172    /**
9173     * Returns all bodies in the given composite, including all bodies in its children, recursively.
9174     * @method allBodies
9175     * @param {composite} composite
9176     * @return {body[]} All the bodies
9177     */
9178    Composite.allBodies = function(composite) {
9179        if (composite.cache && composite.cache.allBodies) {
9180            return composite.cache.allBodies;
9181        }
9182
9183        var bodies = [].concat(composite.bodies);
9184
9185        for (var i = 0; i < composite.composites.length; i++)
9186            bodies = bodies.concat(Composite.allBodies(composite.composites[i]));
9187
9188        if (composite.cache) {
9189            composite.cache.allBodies = bodies;
9190        }
9191
9192        return bodies;
9193    };
9194
9195    /**
9196     * Returns all constraints in the given composite, including all constraints in its children, recursively.
9197     * @method allConstraints
9198     * @param {composite} composite
9199     * @return {constraint[]} All the constraints
9200     */
9201    Composite.allConstraints = function(composite) {
9202        if (composite.cache && composite.cache.allConstraints) {
9203            return composite.cache.allConstraints;
9204        }
9205
9206        var constraints = [].concat(composite.constraints);
9207
9208        for (var i = 0; i < composite.composites.length; i++)
9209            constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));
9210
9211        if (composite.cache) {
9212            composite.cache.allConstraints = constraints;
9213        }
9214
9215        return constraints;
9216    };
9217
9218    /**
9219     * Returns all composites in the given composite, including all composites in its children, recursively.
9220     * @method allComposites
9221     * @param {composite} composite
9222     * @return {composite[]} All the composites
9223     */
9224    Composite.allComposites = function(composite) {
9225        if (composite.cache && composite.cache.allComposites) {
9226            return composite.cache.allComposites;
9227        }
9228
9229        var composites = [].concat(composite.composites);
9230
9231        for (var i = 0; i < composite.composites.length; i++)
9232            composites = composites.concat(Composite.allComposites(composite.composites[i]));
9233
9234        if (composite.cache) {
9235            composite.cache.allComposites = composites;
9236        }
9237
9238        return composites;
9239    };
9240
9241    /**
9242     * Searches the composite recursively for an object matching the type and id supplied, null if not found.
9243     * @method get
9244     * @param {composite} composite
9245     * @param {number} id
9246     * @param {string} type
9247     * @return {object} The requested object, if found
9248     */
9249    Composite.get = function(composite, id, type) {
9250        var objects,
9251            object;
9252
9253        switch (type) {
9254        case 'body':
9255            objects = Composite.allBodies(composite);
9256            break;
9257        case 'constraint':
9258            objects = Composite.allConstraints(composite);
9259            break;
9260        case 'composite':
9261            objects = Composite.allComposites(composite).concat(composite);
9262            break;
9263        }
9264
9265        if (!objects)
9266            return null;
9267
9268        object = objects.filter(function(object) { 
9269            return object.id.toString() === id.toString(); 
9270        });
9271
9272        return object.length === 0 ? null : object[0];
9273    };
9274
9275    /**
9276     * Moves the given object(s) from compositeA to compositeB (equal to a remove followed by an add).
9277     * @method move
9278     * @param {compositeA} compositeA
9279     * @param {object[]} objects
9280     * @param {compositeB} compositeB
9281     * @return {composite} Returns compositeA
9282     */
9283    Composite.move = function(compositeA, objects, compositeB) {
9284        Composite.remove(compositeA, objects);
9285        Composite.add(compositeB, objects);
9286        return compositeA;
9287    };
9288
9289    /**
9290     * Assigns new ids for all objects in the composite, recursively.
9291     * @method rebase
9292     * @param {composite} composite
9293     * @return {composite} Returns composite
9294     */
9295    Composite.rebase = function(composite) {
9296        var objects = Composite.allBodies(composite)
9297            .concat(Composite.allConstraints(composite))
9298            .concat(Composite.allComposites(composite));
9299
9300        for (var i = 0; i < objects.length; i++) {
9301            objects[i].id = Common.nextId();
9302        }
9303
9304        return composite;
9305    };
9306
9307    /**
9308     * Translates all children in the composite by a given vector relative to their current positions, 
9309     * without imparting any velocity.
9310     * @method translate
9311     * @param {composite} composite
9312     * @param {vector} translation
9313     * @param {bool} [recursive=true]
9314     */
9315    Composite.translate = function(composite, translation, recursive) {
9316        var bodies = recursive ? Composite.allBodies(composite) : composite.bodies;
9317
9318        for (var i = 0; i < bodies.length; i++) {
9319            Body.translate(bodies[i], translation);
9320        }
9321
9322        return composite;
9323    };
9324
9325    /**
9326     * Rotates all children in the composite by a given angle about the given point, without imparting any angular velocity.
9327     * @method rotate
9328     * @param {composite} composite
9329     * @param {number} rotation
9330     * @param {vector} point
9331     * @param {bool} [recursive=true]
9332     */
9333    Composite.rotate = function(composite, rotation, point, recursive) {
9334        var cos = Math.cos(rotation),
9335            sin = Math.sin(rotation),
9336            bodies = recursive ? Composite.allBodies(composite) : composite.bodies;
9337
9338        for (var i = 0; i < bodies.length; i++) {
9339            var body = bodies[i],
9340                dx = body.position.x - point.x,
9341                dy = body.position.y - point.y;
9342                
9343            Body.setPosition(body, {
9344                x: point.x + (dx * cos - dy * sin),
9345                y: point.y + (dx * sin + dy * cos)
9346            });
9347
9348            Body.rotate(body, rotation);
9349        }
9350
9351        return composite;
9352    };
9353
9354    /**
9355     * Scales all children in the composite, including updating physical properties (mass, area, axes, inertia), from a world-space point.
9356     * @method scale
9357     * @param {composite} composite
9358     * @param {number} scaleX
9359     * @param {number} scaleY
9360     * @param {vector} point
9361     * @param {bool} [recursive=true]
9362     */
9363    Composite.scale = function(composite, scaleX, scaleY, point, recursive) {
9364        var bodies = recursive ? Composite.allBodies(composite) : composite.bodies;
9365
9366        for (var i = 0; i < bodies.length; i++) {
9367            var body = bodies[i],
9368                dx = body.position.x - point.x,
9369                dy = body.position.y - point.y;
9370                
9371            Body.setPosition(body, {
9372                x: point.x + dx * scaleX,
9373                y: point.y + dy * scaleY
9374            });
9375
9376            Body.scale(body, scaleX, scaleY);
9377        }
9378
9379        return composite;
9380    };
9381
9382    /**
9383     * Returns the union of the bounds of all of the composite's bodies.
9384     * @method bounds
9385     * @param {composite} composite The composite.
9386     * @returns {bounds} The composite bounds.
9387     */
9388    Composite.bounds = function(composite) {
9389        var bodies = Composite.allBodies(composite),
9390            vertices = [];
9391
9392        for (var i = 0; i < bodies.length; i += 1) {
9393            var body = bodies[i];
9394            vertices.push(body.bounds.min, body.bounds.max);
9395        }
9396
9397        return Bounds.create(vertices);
9398    };
9399
9400    /*
9401    *
9402    *  Events Documentation
9403    *
9404    */
9405
9406    /**
9407    * Fired when a call to `Composite.add` is made, before objects have been added.
9408    *
9409    * @event beforeAdd
9410    * @param {} event An event object
9411    * @param {} event.object The object(s) to be added (may be a single body, constraint, composite or a mixed array of these)
9412    * @param {} event.source The source object of the event
9413    * @param {} event.name The name of the event
9414    */
9415
9416    /**
9417    * Fired when a call to `Composite.add` is made, after objects have been added.
9418    *
9419    * @event afterAdd
9420    * @param {} event An event object
9421    * @param {} event.object The object(s) that have been added (may be a single body, constraint, composite or a mixed array of these)
9422    * @param {} event.source The source object of the event
9423    * @param {} event.name The name of the event
9424    */
9425
9426    /**
9427    * Fired when a call to `Composite.remove` is made, before objects have been removed.
9428    *
9429    * @event beforeRemove
9430    * @param {} event An event object
9431    * @param {} event.object The object(s) to be removed (may be a single body, constraint, composite or a mixed array of these)
9432    * @param {} event.source The source object of the event
9433    * @param {} event.name The name of the event
9434    */
9435
9436    /**
9437    * Fired when a call to `Composite.remove` is made, after objects have been removed.
9438    *
9439    * @event afterRemove
9440    * @param {} event An event object
9441    * @param {} event.object The object(s) that have been removed (may be a single body, constraint, composite or a mixed array of these)
9442    * @param {} event.source The source object of the event
9443    * @param {} event.name The name of the event
9444    */
9445
9446    /*
9447    *
9448    *  Properties Documentation
9449    *
9450    */
9451
9452    /**
9453     * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`.
9454     *
9455     * @property id
9456     * @type number
9457     */
9458
9459    /**
9460     * A `String` denoting the type of object.
9461     *
9462     * @property type
9463     * @type string
9464     * @default "composite"
9465     * @readOnly
9466     */
9467
9468    /**
9469     * An arbitrary `String` name to help the user identify and manage composites.
9470     *
9471     * @property label
9472     * @type string
9473     * @default "Composite"
9474     */
9475
9476    /**
9477     * A flag that specifies whether the composite has been modified during the current step.
9478     * This is automatically managed when bodies, constraints or composites are added or removed.
9479     *
9480     * @property isModified
9481     * @type boolean
9482     * @default false
9483     */
9484
9485    /**
9486     * The `Composite` that is the parent of this composite. It is automatically managed by the `Matter.Composite` methods.
9487     *
9488     * @property parent
9489     * @type composite
9490     * @default null
9491     */
9492
9493    /**
9494     * An array of `Body` that are _direct_ children of this composite.
9495     * To add or remove bodies you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.
9496     * If you wish to recursively find all descendants, you should use the `Composite.allBodies` method.
9497     *
9498     * @property bodies
9499     * @type body[]
9500     * @default []
9501     */
9502
9503    /**
9504     * An array of `Constraint` that are _direct_ children of this composite.
9505     * To add or remove constraints you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.
9506     * If you wish to recursively find all descendants, you should use the `Composite.allConstraints` method.
9507     *
9508     * @property constraints
9509     * @type constraint[]
9510     * @default []
9511     */
9512
9513    /**
9514     * An array of `Composite` that are _direct_ children of this composite.
9515     * To add or remove composites you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.
9516     * If you wish to recursively find all descendants, you should use the `Composite.allComposites` method.
9517     *
9518     * @property composites
9519     * @type composite[]
9520     * @default []
9521     */
9522
9523    /**
9524     * An object reserved for storing plugin-specific properties.
9525     *
9526     * @property plugin
9527     * @type {}
9528     */
9529
9530    /**
9531     * An object used for storing cached results for performance reasons.
9532     * This is used internally only and is automatically managed.
9533     *
9534     * @private
9535     * @property cache
9536     * @type {}
9537     */
9538
9539})();
9540
9541
9542/***/ }),
9543/* 7 */
9544/***/ (function(module, exports, __webpack_require__) {
9545
9546/**
9547* The `Matter.Sleeping` module contains methods to manage the sleeping state of bodies.
9548*
9549* @class Sleeping
9550*/
9551
9552var Sleeping = {};
9553
9554module.exports = Sleeping;
9555
9556var Body = __webpack_require__(4);
9557var Events = __webpack_require__(5);
9558var Common = __webpack_require__(0);
9559
9560(function() {
9561
9562    Sleeping._motionWakeThreshold = 0.18;
9563    Sleeping._motionSleepThreshold = 0.08;
9564    Sleeping._minBias = 0.9;
9565
9566    /**
9567     * Puts bodies to sleep or wakes them up depending on their motion.
9568     * @method update
9569     * @param {body[]} bodies
9570     * @param {number} delta
9571     */
9572    Sleeping.update = function(bodies, delta) {
9573        var timeScale = delta / Common._baseDelta,
9574            motionSleepThreshold = Sleeping._motionSleepThreshold;
9575        
9576        // update bodies sleeping status
9577        for (var i = 0; i < bodies.length; i++) {
9578            var body = bodies[i],
9579                speed = Body.getSpeed(body),
9580                angularSpeed = Body.getAngularSpeed(body),
9581                motion = speed * speed + angularSpeed * angularSpeed;
9582
9583            // wake up bodies if they have a force applied
9584            if (body.force.x !== 0 || body.force.y !== 0) {
9585                Sleeping.set(body, false);
9586                continue;
9587            }
9588
9589            var minMotion = Math.min(body.motion, motion),
9590                maxMotion = Math.max(body.motion, motion);
9591        
9592            // biased average motion estimation between frames
9593            body.motion = Sleeping._minBias * minMotion + (1 - Sleeping._minBias) * maxMotion;
9594
9595            if (body.sleepThreshold > 0 && body.motion < motionSleepThreshold) {
9596                body.sleepCounter += 1;
9597                
9598                if (body.sleepCounter >= body.sleepThreshold / timeScale) {
9599                    Sleeping.set(body, true);
9600                }
9601            } else if (body.sleepCounter > 0) {
9602                body.sleepCounter -= 1;
9603            }
9604        }
9605    };
9606
9607    /**
9608     * Given a set of colliding pairs, wakes the sleeping bodies involved.
9609     * @method afterCollisions
9610     * @param {pair[]} pairs
9611     */
9612    Sleeping.afterCollisions = function(pairs) {
9613        var motionSleepThreshold = Sleeping._motionSleepThreshold;
9614
9615        // wake up bodies involved in collisions
9616        for (var i = 0; i < pairs.length; i++) {
9617            var pair = pairs[i];
9618            
9619            // don't wake inactive pairs
9620            if (!pair.isActive)
9621                continue;
9622
9623            var collision = pair.collision,
9624                bodyA = collision.bodyA.parent, 
9625                bodyB = collision.bodyB.parent;
9626        
9627            // don't wake if at least one body is static
9628            if ((bodyA.isSleeping && bodyB.isSleeping) || bodyA.isStatic || bodyB.isStatic)
9629                continue;
9630        
9631            if (bodyA.isSleeping || bodyB.isSleeping) {
9632                var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB,
9633                    movingBody = sleepingBody === bodyA ? bodyB : bodyA;
9634
9635                if (!sleepingBody.isStatic && movingBody.motion > motionSleepThreshold) {
9636                    Sleeping.set(sleepingBody, false);
9637                }
9638            }
9639        }
9640    };
9641  
9642    /**
9643     * Set a body as sleeping or awake.
9644     * @method set
9645     * @param {body} body
9646     * @param {boolean} isSleeping
9647     */
9648    Sleeping.set = function(body, isSleeping) {
9649        var wasSleeping = body.isSleeping;
9650
9651        if (isSleeping) {
9652            body.isSleeping = true;
9653            body.sleepCounter = body.sleepThreshold;
9654
9655            body.positionImpulse.x = 0;
9656            body.positionImpulse.y = 0;
9657
9658            body.positionPrev.x = body.position.x;
9659            body.positionPrev.y = body.position.y;
9660
9661            body.anglePrev = body.angle;
9662            body.speed = 0;
9663            body.angularSpeed = 0;
9664            body.motion = 0;
9665
9666            if (!wasSleeping) {
9667                Events.trigger(body, 'sleepStart');
9668            }
9669        } else {
9670            body.isSleeping = false;
9671            body.sleepCounter = 0;
9672
9673            if (wasSleeping) {
9674                Events.trigger(body, 'sleepEnd');
9675            }
9676        }
9677    };
9678
9679})();
9680
9681
9682/***/ }),
9683/* 8 */
9684/***/ (function(module, exports, __webpack_require__) {
9685
9686/**
9687* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.
9688*
9689* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.
9690*
9691* See `Matter.Engine` for collision events.
9692*
9693* @class Collision
9694*/
9695
9696var Collision = {};
9697
9698module.exports = Collision;
9699
9700var Vertices = __webpack_require__(3);
9701var Pair = __webpack_require__(9);
9702
9703(function() {
9704    var _supports = [];
9705
9706    var _overlapAB = {
9707        overlap: 0,
9708        axis: null
9709    };
9710
9711    var _overlapBA = {
9712        overlap: 0,
9713        axis: null
9714    };
9715
9716    /**
9717     * Creates a new collision record.
9718     * @method create
9719     * @param {body} bodyA The first body part represented by the collision record
9720     * @param {body} bodyB The second body part represented by the collision record
9721     * @return {collision} A new collision record
9722     */
9723    Collision.create = function(bodyA, bodyB) {
9724        return { 
9725            pair: null,
9726            collided: false,
9727            bodyA: bodyA,
9728            bodyB: bodyB,
9729            parentA: bodyA.parent,
9730            parentB: bodyB.parent,
9731            depth: 0,
9732            normal: { x: 0, y: 0 },
9733            tangent: { x: 0, y: 0 },
9734            penetration: { x: 0, y: 0 },
9735            supports: [null, null],
9736            supportCount: 0
9737        };
9738    };
9739
9740    /**
9741     * Detect collision between two bodies.
9742     * @method collides
9743     * @param {body} bodyA
9744     * @param {body} bodyB
9745     * @param {pairs} [pairs] Optionally reuse collision records from existing pairs.
9746     * @return {collision|null} A collision record if detected, otherwise null
9747     */
9748    Collision.collides = function(bodyA, bodyB, pairs) {
9749        Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);
9750
9751        if (_overlapAB.overlap <= 0) {
9752            return null;
9753        }
9754
9755        Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);
9756
9757        if (_overlapBA.overlap <= 0) {
9758            return null;
9759        }
9760
9761        // reuse collision records for gc efficiency
9762        var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],
9763            collision;
9764
9765        if (!pair) {
9766            collision = Collision.create(bodyA, bodyB);
9767            collision.collided = true;
9768            collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;
9769            collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;
9770            collision.parentA = collision.bodyA.parent;
9771            collision.parentB = collision.bodyB.parent;
9772        } else {
9773            collision = pair.collision;
9774        }
9775
9776        bodyA = collision.bodyA;
9777        bodyB = collision.bodyB;
9778
9779        var minOverlap;
9780
9781        if (_overlapAB.overlap < _overlapBA.overlap) {
9782            minOverlap = _overlapAB;
9783        } else {
9784            minOverlap = _overlapBA;
9785        }
9786
9787        var normal = collision.normal,
9788            tangent = collision.tangent,
9789            penetration = collision.penetration,
9790            supports = collision.supports,
9791            depth = minOverlap.overlap,
9792            minAxis = minOverlap.axis,
9793            normalX = minAxis.x,
9794            normalY = minAxis.y,
9795            deltaX = bodyB.position.x - bodyA.position.x,
9796            deltaY = bodyB.position.y - bodyA.position.y;
9797
9798        // ensure normal is facing away from bodyA
9799        if (normalX * deltaX + normalY * deltaY >= 0) {
9800            normalX = -normalX;
9801            normalY = -normalY;
9802        }
9803
9804        normal.x = normalX;
9805        normal.y = normalY;
9806        
9807        tangent.x = -normalY;
9808        tangent.y = normalX;
9809
9810        penetration.x = normalX * depth;
9811        penetration.y = normalY * depth;
9812
9813        collision.depth = depth;
9814
9815        // find support points, there is always either exactly one or two
9816        var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),
9817            supportCount = 0;
9818
9819        // find the supports from bodyB that are inside bodyA
9820        if (Vertices.contains(bodyA.vertices, supportsB[0])) {
9821            supports[supportCount++] = supportsB[0];
9822        }
9823
9824        if (Vertices.contains(bodyA.vertices, supportsB[1])) {
9825            supports[supportCount++] = supportsB[1];
9826        }
9827
9828        // find the supports from bodyA that are inside bodyB
9829        if (supportCount < 2) {
9830            var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1);
9831
9832            if (Vertices.contains(bodyB.vertices, supportsA[0])) {
9833                supports[supportCount++] = supportsA[0];
9834            }
9835
9836            if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {
9837                supports[supportCount++] = supportsA[1];
9838            }
9839        }
9840
9841        // account for the edge case of overlapping but no vertex containment
9842        if (supportCount === 0) {
9843            supports[supportCount++] = supportsB[0];
9844        }
9845
9846        // update support count
9847        collision.supportCount = supportCount;
9848
9849        return collision;
9850    };
9851
9852    /**
9853     * Find the overlap between two sets of vertices.
9854     * @method _overlapAxes
9855     * @private
9856     * @param {object} result
9857     * @param {vertices} verticesA
9858     * @param {vertices} verticesB
9859     * @param {axes} axes
9860     */
9861    Collision._overlapAxes = function(result, verticesA, verticesB, axes) {
9862        var verticesALength = verticesA.length,
9863            verticesBLength = verticesB.length,
9864            verticesAX = verticesA[0].x,
9865            verticesAY = verticesA[0].y,
9866            verticesBX = verticesB[0].x,
9867            verticesBY = verticesB[0].y,
9868            axesLength = axes.length,
9869            overlapMin = Number.MAX_VALUE,
9870            overlapAxisNumber = 0,
9871            overlap,
9872            overlapAB,
9873            overlapBA,
9874            dot,
9875            i,
9876            j;
9877
9878        for (i = 0; i < axesLength; i++) {
9879            var axis = axes[i],
9880                axisX = axis.x,
9881                axisY = axis.y,
9882                minA = verticesAX * axisX + verticesAY * axisY,
9883                minB = verticesBX * axisX + verticesBY * axisY,
9884                maxA = minA,
9885                maxB = minB;
9886            
9887            for (j = 1; j < verticesALength; j += 1) {
9888                dot = verticesA[j].x * axisX + verticesA[j].y * axisY;
9889
9890                if (dot > maxA) { 
9891                    maxA = dot;
9892                } else if (dot < minA) { 
9893                    minA = dot;
9894                }
9895            }
9896
9897            for (j = 1; j < verticesBLength; j += 1) {
9898                dot = verticesB[j].x * axisX + verticesB[j].y * axisY;
9899
9900                if (dot > maxB) { 
9901                    maxB = dot;
9902                } else if (dot < minB) { 
9903                    minB = dot;
9904                }
9905            }
9906
9907            overlapAB = maxA - minB;
9908            overlapBA = maxB - minA;
9909            overlap = overlapAB < overlapBA ? overlapAB : overlapBA;
9910
9911            if (overlap < overlapMin) {
9912                overlapMin = overlap;
9913                overlapAxisNumber = i;
9914
9915                if (overlap <= 0) {
9916                    // can not be intersecting
9917                    break;
9918                }
9919            } 
9920        }
9921
9922        result.axis = axes[overlapAxisNumber];
9923        result.overlap = overlapMin;
9924    };
9925
9926    /**
9927     * Finds supporting vertices given two bodies along a given direction using hill-climbing.
9928     * @method _findSupports
9929     * @private
9930     * @param {body} bodyA
9931     * @param {body} bodyB
9932     * @param {vector} normal
9933     * @param {number} direction
9934     * @return [vector]
9935     */
9936    Collision._findSupports = function(bodyA, bodyB, normal, direction) {
9937        var vertices = bodyB.vertices,
9938            verticesLength = vertices.length,
9939            bodyAPositionX = bodyA.position.x,
9940            bodyAPositionY = bodyA.position.y,
9941            normalX = normal.x * direction,
9942            normalY = normal.y * direction,
9943            vertexA = vertices[0],
9944            vertexB = vertexA,
9945            nearestDistance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y),
9946            vertexC,
9947            distance,
9948            j;
9949
9950        // find deepest vertex relative to the axis
9951        for (j = 1; j < verticesLength; j += 1) {
9952            vertexB = vertices[j];
9953            distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);
9954
9955            // convex hill-climbing
9956            if (distance < nearestDistance) {
9957                nearestDistance = distance;
9958                vertexA = vertexB;
9959            }
9960        }
9961
9962        // measure next vertex
9963        vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];
9964        nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);
9965
9966        // compare with previous vertex
9967        vertexB = vertices[(vertexA.index + 1) % verticesLength];
9968        if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {
9969            _supports[0] = vertexA;
9970            _supports[1] = vertexB;
9971
9972            return _supports;
9973        }
9974
9975        _supports[0] = vertexA;
9976        _supports[1] = vertexC;
9977
9978        return _supports;
9979    };
9980
9981    /*
9982    *
9983    *  Properties Documentation
9984    *
9985    */
9986
9987    /**
9988     * A reference to the pair using this collision record, if there is one.
9989     *
9990     * @property pair
9991     * @type {pair|null}
9992     * @default null
9993     */
9994
9995    /**
9996     * A flag that indicates if the bodies were colliding when the collision was last updated.
9997     * 
9998     * @property collided
9999     * @type boolean
10000     * @default false
10001     */
10002
10003    /**
10004     * The first body part represented by the collision (see also `collision.parentA`).
10005     * 
10006     * @property bodyA
10007     * @type body
10008     */
10009
10010    /**
10011     * The second body part represented by the collision (see also `collision.parentB`).
10012     * 
10013     * @property bodyB
10014     * @type body
10015     */
10016
10017    /**
10018     * The first body represented by the collision (i.e. `collision.bodyA.parent`).
10019     * 
10020     * @property parentA
10021     * @type body
10022     */
10023
10024    /**
10025     * The second body represented by the collision (i.e. `collision.bodyB.parent`).
10026     * 
10027     * @property parentB
10028     * @type body
10029     */
10030
10031    /**
10032     * A `Number` that represents the minimum separating distance between the bodies along the collision normal.
10033     *
10034     * @readOnly
10035     * @property depth
10036     * @type number
10037     * @default 0
10038     */
10039
10040    /**
10041     * A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance.
10042     *
10043     * @property normal
10044     * @type vector
10045     * @default { x: 0, y: 0 }
10046     */
10047
10048    /**
10049     * A normalised `Vector` that is the tangent direction to the collision normal.
10050     *
10051     * @property tangent
10052     * @type vector
10053     * @default { x: 0, y: 0 }
10054     */
10055
10056    /**
10057     * A `Vector` that represents the direction and depth of the collision.
10058     *
10059     * @property penetration
10060     * @type vector
10061     * @default { x: 0, y: 0 }
10062     */
10063
10064    /**
10065     * An array of body vertices that represent the support points in the collision.
10066     * 
10067     * _Note:_ Only the first `collision.supportCount` items of `collision.supports` are active.
10068     * Therefore use `collision.supportCount` instead of `collision.supports.length` when iterating the active supports.
10069     * 
10070     * These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.
10071     *
10072     * @property supports
10073     * @type vector[]
10074     * @default []
10075     */
10076
10077    /**
10078     * The number of active supports for this collision found in `collision.supports`.
10079     * 
10080     * _Note:_ Only the first `collision.supportCount` items of `collision.supports` are active.
10081     * Therefore use `collision.supportCount` instead of `collision.supports.length` when iterating the active supports.
10082     *
10083     * @property supportCount
10084     * @type number
10085     * @default 0
10086     */
10087
10088})();
10089
10090
10091/***/ }),
10092/* 9 */
10093/***/ (function(module, exports, __webpack_require__) {
10094
10095/**
10096* The `Matter.Pair` module contains methods for creating and manipulating collision pairs.
10097*
10098* @class Pair
10099*/
10100
10101var Pair = {};
10102
10103module.exports = Pair;
10104
10105var Contact = __webpack_require__(16);
10106
10107(function() {
10108    
10109    /**
10110     * Creates a pair.
10111     * @method create
10112     * @param {collision} collision
10113     * @param {number} timestamp
10114     * @return {pair} A new pair
10115     */
10116    Pair.create = function(collision, timestamp) {
10117        var bodyA = collision.bodyA,
10118            bodyB = collision.bodyB;
10119
10120        var pair = {
10121            id: Pair.id(bodyA, bodyB),
10122            bodyA: bodyA,
10123            bodyB: bodyB,
10124            collision: collision,
10125            contacts: [Contact.create(), Contact.create()],
10126            contactCount: 0,
10127            separation: 0,
10128            isActive: true,
10129            isSensor: bodyA.isSensor || bodyB.isSensor,
10130            timeCreated: timestamp,
10131            timeUpdated: timestamp,
10132            inverseMass: 0,
10133            friction: 0,
10134            frictionStatic: 0,
10135            restitution: 0,
10136            slop: 0
10137        };
10138
10139        Pair.update(pair, collision, timestamp);
10140
10141        return pair;
10142    };
10143
10144    /**
10145     * Updates a pair given a collision.
10146     * @method update
10147     * @param {pair} pair
10148     * @param {collision} collision
10149     * @param {number} timestamp
10150     */
10151    Pair.update = function(pair, collision, timestamp) {
10152        var supports = collision.supports,
10153            supportCount = collision.supportCount,
10154            contacts = pair.contacts,
10155            parentA = collision.parentA,
10156            parentB = collision.parentB;
10157        
10158        pair.isActive = true;
10159        pair.timeUpdated = timestamp;
10160        pair.collision = collision;
10161        pair.separation = collision.depth;
10162        pair.inverseMass = parentA.inverseMass + parentB.inverseMass;
10163        pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction;
10164        pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic;
10165        pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution;
10166        pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop;
10167
10168        pair.contactCount = supportCount;
10169        collision.pair = pair;
10170
10171        var supportA = supports[0],
10172            contactA = contacts[0],
10173            supportB = supports[1],
10174            contactB = contacts[1];
10175
10176        // match contacts to supports
10177        if (contactB.vertex === supportA || contactA.vertex === supportB) {
10178            contacts[1] = contactA;
10179            contacts[0] = contactA = contactB;
10180            contactB = contacts[1];
10181        }
10182
10183        // update contacts
10184        contactA.vertex = supportA;
10185        contactB.vertex = supportB;
10186    };
10187    
10188    /**
10189     * Set a pair as active or inactive.
10190     * @method setActive
10191     * @param {pair} pair
10192     * @param {bool} isActive
10193     * @param {number} timestamp
10194     */
10195    Pair.setActive = function(pair, isActive, timestamp) {
10196        if (isActive) {
10197            pair.isActive = true;
10198            pair.timeUpdated = timestamp;
10199        } else {
10200            pair.isActive = false;
10201            pair.contactCount = 0;
10202        }
10203    };
10204
10205    /**
10206     * Get the id for the given pair.
10207     * @method id
10208     * @param {body} bodyA
10209     * @param {body} bodyB
10210     * @return {string} Unique pairId
10211     */
10212    Pair.id = function(bodyA, bodyB) {
10213        return bodyA.id < bodyB.id ? bodyA.id.toString(36) + ':' + bodyB.id.toString(36) 
10214            : bodyB.id.toString(36) + ':' + bodyA.id.toString(36);
10215    };
10216
10217})();
10218
10219
10220/***/ }),
10221/* 10 */
10222/***/ (function(module, exports, __webpack_require__) {
10223
10224/**
10225* The `Matter.Constraint` module contains methods for creating and manipulating constraints.
10226* Constraints are used for specifying that a fixed distance must be maintained between two bodies (or a body and a fixed world-space position).
10227* The stiffness of constraints can be modified to create springs or elastic.
10228*
10229* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
10230*
10231* @class Constraint
10232*/
10233
10234var Constraint = {};
10235
10236module.exports = Constraint;
10237
10238var Vertices = __webpack_require__(3);
10239var Vector = __webpack_require__(2);
10240var Sleeping = __webpack_require__(7);
10241var Bounds = __webpack_require__(1);
10242var Axes = __webpack_require__(11);
10243var Common = __webpack_require__(0);
10244
10245(function() {
10246
10247    Constraint._warming = 0.4;
10248    Constraint._torqueDampen = 1;
10249    Constraint._minLength = 0.000001;
10250
10251    /**
10252     * Creates a new constraint.
10253     * All properties have default values, and many are pre-calculated automatically based on other properties.
10254     * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above).
10255     * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`.
10256     * For compound bodies, constraints must be applied to the parent body (not one of its parts).
10257     * See the properties section below for detailed information on what you can pass via the `options` object.
10258     * @method create
10259     * @param {} options
10260     * @return {constraint} constraint
10261     */
10262    Constraint.create = function(options) {
10263        var constraint = options;
10264
10265        // if bodies defined but no points, use body centre
10266        if (constraint.bodyA && !constraint.pointA)
10267            constraint.pointA = { x: 0, y: 0 };
10268        if (constraint.bodyB && !constraint.pointB)
10269            constraint.pointB = { x: 0, y: 0 };
10270
10271        // calculate static length using initial world space points
10272        var initialPointA = constraint.bodyA ? Vector.add(constraint.bodyA.position, constraint.pointA) : constraint.pointA,
10273            initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB,
10274            length = Vector.magnitude(Vector.sub(initialPointA, initialPointB));
10275    
10276        constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length;
10277
10278        // option defaults
10279        constraint.id = constraint.id || Common.nextId();
10280        constraint.label = constraint.label || 'Constraint';
10281        constraint.type = 'constraint';
10282        constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7);
10283        constraint.damping = constraint.damping || 0;
10284        constraint.angularStiffness = constraint.angularStiffness || 0;
10285        constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA;
10286        constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB;
10287        constraint.plugin = {};
10288
10289        // render
10290        var render = {
10291            visible: true,
10292            lineWidth: 2,
10293            strokeStyle: '#ffffff',
10294            type: 'line',
10295            anchors: true
10296        };
10297
10298        if (constraint.length === 0 && constraint.stiffness > 0.1) {
10299            render.type = 'pin';
10300            render.anchors = false;
10301        } else if (constraint.stiffness < 0.9) {
10302            render.type = 'spring';
10303        }
10304
10305        constraint.render = Common.extend(render, constraint.render);
10306
10307        return constraint;
10308    };
10309
10310    /**
10311     * Prepares for solving by constraint warming.
10312     * @private
10313     * @method preSolveAll
10314     * @param {body[]} bodies
10315     */
10316    Constraint.preSolveAll = function(bodies) {
10317        for (var i = 0; i < bodies.length; i += 1) {
10318            var body = bodies[i],
10319                impulse = body.constraintImpulse;
10320
10321            if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) {
10322                continue;
10323            }
10324
10325            body.position.x += impulse.x;
10326            body.position.y += impulse.y;
10327            body.angle += impulse.angle;
10328        }
10329    };
10330
10331    /**
10332     * Solves all constraints in a list of collisions.
10333     * @private
10334     * @method solveAll
10335     * @param {constraint[]} constraints
10336     * @param {number} delta
10337     */
10338    Constraint.solveAll = function(constraints, delta) {
10339        var timeScale = Common.clamp(delta / Common._baseDelta, 0, 1);
10340
10341        // Solve fixed constraints first.
10342        for (var i = 0; i < constraints.length; i += 1) {
10343            var constraint = constraints[i],
10344                fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic),
10345                fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic);
10346
10347            if (fixedA || fixedB) {
10348                Constraint.solve(constraints[i], timeScale);
10349            }
10350        }
10351
10352        // Solve free constraints last.
10353        for (i = 0; i < constraints.length; i += 1) {
10354            constraint = constraints[i];
10355            fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic);
10356            fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic);
10357
10358            if (!fixedA && !fixedB) {
10359                Constraint.solve(constraints[i], timeScale);
10360            }
10361        }
10362    };
10363
10364    /**
10365     * Solves a distance constraint with Gauss-Siedel method.
10366     * @private
10367     * @method solve
10368     * @param {constraint} constraint
10369     * @param {number} timeScale
10370     */
10371    Constraint.solve = function(constraint, timeScale) {
10372        var bodyA = constraint.bodyA,
10373            bodyB = constraint.bodyB,
10374            pointA = constraint.pointA,
10375            pointB = constraint.pointB;
10376
10377        if (!bodyA && !bodyB)
10378            return;
10379
10380        // update reference angle
10381        if (bodyA && !bodyA.isStatic) {
10382            Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA);
10383            constraint.angleA = bodyA.angle;
10384        }
10385        
10386        // update reference angle
10387        if (bodyB && !bodyB.isStatic) {
10388            Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB);
10389            constraint.angleB = bodyB.angle;
10390        }
10391
10392        var pointAWorld = pointA,
10393            pointBWorld = pointB;
10394
10395        if (bodyA) pointAWorld = Vector.add(bodyA.position, pointA);
10396        if (bodyB) pointBWorld = Vector.add(bodyB.position, pointB);
10397
10398        if (!pointAWorld || !pointBWorld)
10399            return;
10400
10401        var delta = Vector.sub(pointAWorld, pointBWorld),
10402            currentLength = Vector.magnitude(delta);
10403
10404        // prevent singularity
10405        if (currentLength < Constraint._minLength) {
10406            currentLength = Constraint._minLength;
10407        }
10408
10409        // solve distance constraint with Gauss-Siedel method
10410        var difference = (currentLength - constraint.length) / currentLength,
10411            isRigid = constraint.stiffness >= 1 || constraint.length === 0,
10412            stiffness = isRigid ? constraint.stiffness * timeScale 
10413                : constraint.stiffness * timeScale * timeScale,
10414            damping = constraint.damping * timeScale,
10415            force = Vector.mult(delta, difference * stiffness),
10416            massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0),
10417            inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0),
10418            resistanceTotal = massTotal + inertiaTotal,
10419            torque,
10420            share,
10421            normal,
10422            normalVelocity,
10423            relativeVelocity;
10424    
10425        if (damping > 0) {
10426            var zero = Vector.create();
10427            normal = Vector.div(delta, currentLength);
10428
10429            relativeVelocity = Vector.sub(
10430                bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero,
10431                bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero
10432            );
10433
10434            normalVelocity = Vector.dot(normal, relativeVelocity);
10435        }
10436
10437        if (bodyA && !bodyA.isStatic) {
10438            share = bodyA.inverseMass / massTotal;
10439
10440            // keep track of applied impulses for post solving
10441            bodyA.constraintImpulse.x -= force.x * share;
10442            bodyA.constraintImpulse.y -= force.y * share;
10443
10444            // apply forces
10445            bodyA.position.x -= force.x * share;
10446            bodyA.position.y -= force.y * share;
10447
10448            // apply damping
10449            if (damping > 0) {
10450                bodyA.positionPrev.x -= damping * normal.x * normalVelocity * share;
10451                bodyA.positionPrev.y -= damping * normal.y * normalVelocity * share;
10452            }
10453
10454            // apply torque
10455            torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness);
10456            bodyA.constraintImpulse.angle -= torque;
10457            bodyA.angle -= torque;
10458        }
10459
10460        if (bodyB && !bodyB.isStatic) {
10461            share = bodyB.inverseMass / massTotal;
10462
10463            // keep track of applied impulses for post solving
10464            bodyB.constraintImpulse.x += force.x * share;
10465            bodyB.constraintImpulse.y += force.y * share;
10466            
10467            // apply forces
10468            bodyB.position.x += force.x * share;
10469            bodyB.position.y += force.y * share;
10470
10471            // apply damping
10472            if (damping > 0) {
10473                bodyB.positionPrev.x += damping * normal.x * normalVelocity * share;
10474                bodyB.positionPrev.y += damping * normal.y * normalVelocity * share;
10475            }
10476
10477            // apply torque
10478            torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness);
10479            bodyB.constraintImpulse.angle += torque;
10480            bodyB.angle += torque;
10481        }
10482
10483    };
10484
10485    /**
10486     * Performs body updates required after solving constraints.
10487     * @private
10488     * @method postSolveAll
10489     * @param {body[]} bodies
10490     */
10491    Constraint.postSolveAll = function(bodies) {
10492        for (var i = 0; i < bodies.length; i++) {
10493            var body = bodies[i],
10494                impulse = body.constraintImpulse;
10495
10496            if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) {
10497                continue;
10498            }
10499
10500            Sleeping.set(body, false);
10501
10502            // update geometry and reset
10503            for (var j = 0; j < body.parts.length; j++) {
10504                var part = body.parts[j];
10505                
10506                Vertices.translate(part.vertices, impulse);
10507
10508                if (j > 0) {
10509                    part.position.x += impulse.x;
10510                    part.position.y += impulse.y;
10511                }
10512
10513                if (impulse.angle !== 0) {
10514                    Vertices.rotate(part.vertices, impulse.angle, body.position);
10515                    Axes.rotate(part.axes, impulse.angle);
10516                    if (j > 0) {
10517                        Vector.rotateAbout(part.position, impulse.angle, body.position, part.position);
10518                    }
10519                }
10520
10521                Bounds.update(part.bounds, part.vertices, body.velocity);
10522            }
10523
10524            // dampen the cached impulse for warming next step
10525            impulse.angle *= Constraint._warming;
10526            impulse.x *= Constraint._warming;
10527            impulse.y *= Constraint._warming;
10528        }
10529    };
10530
10531    /**
10532     * Returns the world-space position of `constraint.pointA`, accounting for `constraint.bodyA`.
10533     * @method pointAWorld
10534     * @param {constraint} constraint
10535     * @returns {vector} the world-space position
10536     */
10537    Constraint.pointAWorld = function(constraint) {
10538        return {
10539            x: (constraint.bodyA ? constraint.bodyA.position.x : 0) 
10540                + (constraint.pointA ? constraint.pointA.x : 0),
10541            y: (constraint.bodyA ? constraint.bodyA.position.y : 0) 
10542                + (constraint.pointA ? constraint.pointA.y : 0)
10543        };
10544    };
10545
10546    /**
10547     * Returns the world-space position of `constraint.pointB`, accounting for `constraint.bodyB`.
10548     * @method pointBWorld
10549     * @param {constraint} constraint
10550     * @returns {vector} the world-space position
10551     */
10552    Constraint.pointBWorld = function(constraint) {
10553        return {
10554            x: (constraint.bodyB ? constraint.bodyB.position.x : 0) 
10555                + (constraint.pointB ? constraint.pointB.x : 0),
10556            y: (constraint.bodyB ? constraint.bodyB.position.y : 0) 
10557                + (constraint.pointB ? constraint.pointB.y : 0)
10558        };
10559    };
10560
10561    /**
10562     * Returns the current length of the constraint. 
10563     * This is the distance between both of the constraint's end points.
10564     * See `constraint.length` for the target rest length.
10565     * @method currentLength
10566     * @param {constraint} constraint
10567     * @returns {number} the current length
10568     */
10569    Constraint.currentLength = function(constraint) {
10570        var pointAX = (constraint.bodyA ? constraint.bodyA.position.x : 0) 
10571            + (constraint.pointA ? constraint.pointA.x : 0);
10572
10573        var pointAY = (constraint.bodyA ? constraint.bodyA.position.y : 0) 
10574            + (constraint.pointA ? constraint.pointA.y : 0);
10575
10576        var pointBX = (constraint.bodyB ? constraint.bodyB.position.x : 0) 
10577            + (constraint.pointB ? constraint.pointB.x : 0);
10578            
10579        var pointBY = (constraint.bodyB ? constraint.bodyB.position.y : 0) 
10580            + (constraint.pointB ? constraint.pointB.y : 0);
10581
10582        var deltaX = pointAX - pointBX;
10583        var deltaY = pointAY - pointBY;
10584
10585        return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
10586    };
10587
10588    /*
10589    *
10590    *  Properties Documentation
10591    *
10592    */
10593
10594    /**
10595     * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`.
10596     *
10597     * @property id
10598     * @type number
10599     */
10600
10601    /**
10602     * A `String` denoting the type of object.
10603     *
10604     * @property type
10605     * @type string
10606     * @default "constraint"
10607     * @readOnly
10608     */
10609
10610    /**
10611     * An arbitrary `String` name to help the user identify and manage bodies.
10612     *
10613     * @property label
10614     * @type string
10615     * @default "Constraint"
10616     */
10617
10618    /**
10619     * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`.
10620     *
10621     * @property render
10622     * @type object
10623     */
10624
10625    /**
10626     * A flag that indicates if the constraint should be rendered.
10627     *
10628     * @property render.visible
10629     * @type boolean
10630     * @default true
10631     */
10632
10633    /**
10634     * A `Number` that defines the line width to use when rendering the constraint outline.
10635     * A value of `0` means no outline will be rendered.
10636     *
10637     * @property render.lineWidth
10638     * @type number
10639     * @default 2
10640     */
10641
10642    /**
10643     * A `String` that defines the stroke style to use when rendering the constraint outline.
10644     * It is the same as when using a canvas, so it accepts CSS style property values.
10645     *
10646     * @property render.strokeStyle
10647     * @type string
10648     * @default a random colour
10649     */
10650
10651    /**
10652     * A `String` that defines the constraint rendering type. 
10653     * The possible values are 'line', 'pin', 'spring'.
10654     * An appropriate render type will be automatically chosen unless one is given in options.
10655     *
10656     * @property render.type
10657     * @type string
10658     * @default 'line'
10659     */
10660
10661    /**
10662     * A `Boolean` that defines if the constraint's anchor points should be rendered.
10663     *
10664     * @property render.anchors
10665     * @type boolean
10666     * @default true
10667     */
10668
10669    /**
10670     * The first possible `Body` that this constraint is attached to.
10671     *
10672     * @property bodyA
10673     * @type body
10674     * @default null
10675     */
10676
10677    /**
10678     * The second possible `Body` that this constraint is attached to.
10679     *
10680     * @property bodyB
10681     * @type body
10682     * @default null
10683     */
10684
10685    /**
10686     * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyA` if defined, otherwise a world-space position.
10687     *
10688     * @property pointA
10689     * @type vector
10690     * @default { x: 0, y: 0 }
10691     */
10692
10693    /**
10694     * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyB` if defined, otherwise a world-space position.
10695     *
10696     * @property pointB
10697     * @type vector
10698     * @default { x: 0, y: 0 }
10699     */
10700
10701    /**
10702     * A `Number` that specifies the stiffness of the constraint, i.e. the rate at which it returns to its resting `constraint.length`.
10703     * A value of `1` means the constraint should be very stiff.
10704     * A value of `0.2` means the constraint acts like a soft spring.
10705     *
10706     * @property stiffness
10707     * @type number
10708     * @default 1
10709     */
10710
10711    /**
10712     * A `Number` that specifies the damping of the constraint, 
10713     * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation.
10714     * Damping will only be apparent when the constraint also has a very low `stiffness`.
10715     * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation.
10716     * A value of `0` means the constraint will apply no damping.
10717     *
10718     * @property damping
10719     * @type number
10720     * @default 0
10721     */
10722
10723    /**
10724     * A `Number` that specifies the target resting length of the constraint. 
10725     * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`.
10726     *
10727     * @property length
10728     * @type number
10729     */
10730
10731    /**
10732     * An object reserved for storing plugin-specific properties.
10733     *
10734     * @property plugin
10735     * @type {}
10736     */
10737
10738})();
10739
10740
10741/***/ }),
10742/* 11 */
10743/***/ (function(module, exports, __webpack_require__) {
10744
10745/**
10746* The `Matter.Axes` module contains methods for creating and manipulating sets of axes.
10747*
10748* @class Axes
10749*/
10750
10751var Axes = {};
10752
10753module.exports = Axes;
10754
10755var Vector = __webpack_require__(2);
10756var Common = __webpack_require__(0);
10757
10758(function() {
10759
10760    /**
10761     * Creates a new set of axes from the given vertices.
10762     * @method fromVertices
10763     * @param {vertices} vertices
10764     * @return {axes} A new axes from the given vertices
10765     */
10766    Axes.fromVertices = function(vertices) {
10767        var axes = {};
10768
10769        // find the unique axes, using edge normal gradients
10770        for (var i = 0; i < vertices.length; i++) {
10771            var j = (i + 1) % vertices.length, 
10772                normal = Vector.normalise({ 
10773                    x: vertices[j].y - vertices[i].y, 
10774                    y: vertices[i].x - vertices[j].x
10775                }),
10776                gradient = (normal.y === 0) ? Infinity : (normal.x / normal.y);
10777            
10778            // limit precision
10779            gradient = gradient.toFixed(3).toString();
10780            axes[gradient] = normal;
10781        }
10782
10783        return Common.values(axes);
10784    };
10785
10786    /**
10787     * Rotates a set of axes by the given angle.
10788     * @method rotate
10789     * @param {axes} axes
10790     * @param {number} angle
10791     */
10792    Axes.rotate = function(axes, angle) {
10793        if (angle === 0)
10794            return;
10795        
10796        var cos = Math.cos(angle),
10797            sin = Math.sin(angle);
10798
10799        for (var i = 0; i < axes.length; i++) {
10800            var axis = axes[i],
10801                xx;
10802            xx = axis.x * cos - axis.y * sin;
10803            axis.y = axis.x * sin + axis.y * cos;
10804            axis.x = xx;
10805        }
10806    };
10807
10808})();
10809
10810
10811/***/ }),
10812/* 12 */
10813/***/ (function(module, exports, __webpack_require__) {
10814
10815/**
10816* The `Matter.Bodies` module contains factory methods for creating rigid body models 
10817* with commonly used body configurations (such as rectangles, circles and other polygons).
10818*
10819* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
10820*
10821* @class Bodies
10822*/
10823
10824// TODO: true circle bodies
10825
10826var Bodies = {};
10827
10828module.exports = Bodies;
10829
10830var Vertices = __webpack_require__(3);
10831var Common = __webpack_require__(0);
10832var Body = __webpack_require__(4);
10833var Bounds = __webpack_require__(1);
10834var Vector = __webpack_require__(2);
10835
10836(function() {
10837
10838    /**
10839     * Creates a new rigid body model with a rectangle hull. 
10840     * The options parameter is an object that specifies any properties you wish to override the defaults.
10841     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
10842     * @method rectangle
10843     * @param {number} x
10844     * @param {number} y
10845     * @param {number} width
10846     * @param {number} height
10847     * @param {object} [options]
10848     * @return {body} A new rectangle body
10849     */
10850    Bodies.rectangle = function(x, y, width, height, options) {
10851        options = options || {};
10852
10853        var rectangle = { 
10854            label: 'Rectangle Body',
10855            position: { x: x, y: y },
10856            vertices: Vertices.fromPath('L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height)
10857        };
10858
10859        if (options.chamfer) {
10860            var chamfer = options.chamfer;
10861            rectangle.vertices = Vertices.chamfer(rectangle.vertices, chamfer.radius, 
10862                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);
10863            delete options.chamfer;
10864        }
10865
10866        return Body.create(Common.extend({}, rectangle, options));
10867    };
10868    
10869    /**
10870     * Creates a new rigid body model with a trapezoid hull. 
10871     * The `slope` is parameterised as a fraction of `width` and must be < 1 to form a valid trapezoid. 
10872     * The options parameter is an object that specifies any properties you wish to override the defaults.
10873     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
10874     * @method trapezoid
10875     * @param {number} x
10876     * @param {number} y
10877     * @param {number} width
10878     * @param {number} height
10879     * @param {number} slope Must be a number < 1.
10880     * @param {object} [options]
10881     * @return {body} A new trapezoid body
10882     */
10883    Bodies.trapezoid = function(x, y, width, height, slope, options) {
10884        options = options || {};
10885
10886        if (slope >= 1) {
10887            Common.warn('Bodies.trapezoid: slope parameter must be < 1.');
10888        }
10889
10890        slope *= 0.5;
10891        var roof = (1 - (slope * 2)) * width;
10892        
10893        var x1 = width * slope,
10894            x2 = x1 + roof,
10895            x3 = x2 + x1,
10896            verticesPath;
10897
10898        if (slope < 0.5) {
10899            verticesPath = 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0';
10900        } else {
10901            verticesPath = 'L 0 0 L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0';
10902        }
10903
10904        var trapezoid = { 
10905            label: 'Trapezoid Body',
10906            position: { x: x, y: y },
10907            vertices: Vertices.fromPath(verticesPath)
10908        };
10909
10910        if (options.chamfer) {
10911            var chamfer = options.chamfer;
10912            trapezoid.vertices = Vertices.chamfer(trapezoid.vertices, chamfer.radius, 
10913                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);
10914            delete options.chamfer;
10915        }
10916
10917        return Body.create(Common.extend({}, trapezoid, options));
10918    };
10919
10920    /**
10921     * Creates a new rigid body model with a circle hull. 
10922     * The options parameter is an object that specifies any properties you wish to override the defaults.
10923     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
10924     * @method circle
10925     * @param {number} x
10926     * @param {number} y
10927     * @param {number} radius
10928     * @param {object} [options]
10929     * @param {number} [maxSides]
10930     * @return {body} A new circle body
10931     */
10932    Bodies.circle = function(x, y, radius, options, maxSides) {
10933        options = options || {};
10934
10935        var circle = {
10936            label: 'Circle Body',
10937            circleRadius: radius
10938        };
10939        
10940        // approximate circles with polygons until true circles implemented in SAT
10941        maxSides = maxSides || 25;
10942        var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius)));
10943
10944        // optimisation: always use even number of sides (half the number of unique axes)
10945        if (sides % 2 === 1)
10946            sides += 1;
10947
10948        return Bodies.polygon(x, y, sides, radius, Common.extend({}, circle, options));
10949    };
10950
10951    /**
10952     * Creates a new rigid body model with a regular polygon hull with the given number of sides. 
10953     * The options parameter is an object that specifies any properties you wish to override the defaults.
10954     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
10955     * @method polygon
10956     * @param {number} x
10957     * @param {number} y
10958     * @param {number} sides
10959     * @param {number} radius
10960     * @param {object} [options]
10961     * @return {body} A new regular polygon body
10962     */
10963    Bodies.polygon = function(x, y, sides, radius, options) {
10964        options = options || {};
10965
10966        if (sides < 3)
10967            return Bodies.circle(x, y, radius, options);
10968
10969        var theta = 2 * Math.PI / sides,
10970            path = '',
10971            offset = theta * 0.5;
10972
10973        for (var i = 0; i < sides; i += 1) {
10974            var angle = offset + (i * theta),
10975                xx = Math.cos(angle) * radius,
10976                yy = Math.sin(angle) * radius;
10977
10978            path += 'L ' + xx.toFixed(3) + ' ' + yy.toFixed(3) + ' ';
10979        }
10980
10981        var polygon = { 
10982            label: 'Polygon Body',
10983            position: { x: x, y: y },
10984            vertices: Vertices.fromPath(path)
10985        };
10986
10987        if (options.chamfer) {
10988            var chamfer = options.chamfer;
10989            polygon.vertices = Vertices.chamfer(polygon.vertices, chamfer.radius, 
10990                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);
10991            delete options.chamfer;
10992        }
10993
10994        return Body.create(Common.extend({}, polygon, options));
10995    };
10996
10997    /**
10998     * Utility to create a compound body based on set(s) of vertices.
10999     * 
11000     * _Note:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js) 
11001     * package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used.
11002     * 
11003     * The resulting vertices are reorientated about their centre of mass,
11004     * and offset such that `body.position` corresponds to this point.
11005     * 
11006     * The resulting offset may be found if needed by subtracting `body.bounds` from the original input bounds.
11007     * To later move the centre of mass see `Body.setCentre`.
11008     * 
11009     * Note that automatic conconcave decomposition results are not always optimal. 
11010     * For best results, simplify the input vertices as much as possible first.
11011     * By default this function applies some addtional simplification to help.
11012     * 
11013     * Some outputs may also require further manual processing afterwards to be robust.
11014     * In particular some parts may need to be overlapped to avoid collision gaps.
11015     * Thin parts and sharp points should be avoided or removed where possible.
11016     *
11017     * The options parameter object specifies any `Matter.Body` properties you wish to override the defaults.
11018     * 
11019     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.
11020     * @method fromVertices
11021     * @param {number} x
11022     * @param {number} y
11023     * @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`.
11024     * @param {object} [options] The body options.
11025     * @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`.
11026     * @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge.
11027     * @param {number} [minimumArea=10] Threshold when removing small parts.
11028     * @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices.
11029     * @return {body}
11030     */
11031    Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {
11032        var decomp = Common.getDecomp(),
11033            canDecomp,
11034            body,
11035            parts,
11036            isConvex,
11037            isConcave,
11038            vertices,
11039            i,
11040            j,
11041            k,
11042            v,
11043            z;
11044
11045        // check decomp is as expected
11046        canDecomp = Boolean(decomp && decomp.quickDecomp);
11047
11048        options = options || {};
11049        parts = [];
11050
11051        flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;
11052        removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;
11053        minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;
11054        removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01;
11055
11056        // ensure vertexSets is an array of arrays
11057        if (!Common.isArray(vertexSets[0])) {
11058            vertexSets = [vertexSets];
11059        }
11060
11061        for (v = 0; v < vertexSets.length; v += 1) {
11062            vertices = vertexSets[v];
11063            isConvex = Vertices.isConvex(vertices);
11064            isConcave = !isConvex;
11065
11066            if (isConcave && !canDecomp) {
11067                Common.warnOnce(
11068                    'Bodies.fromVertices: Install the \'poly-decomp\' library and use Common.setDecomp or provide \'decomp\' as a global to decompose concave vertices.'
11069                );
11070            }
11071
11072            if (isConvex || !canDecomp) {
11073                if (isConvex) {
11074                    vertices = Vertices.clockwiseSort(vertices);
11075                } else {
11076                    // fallback to convex hull when decomposition is not possible
11077                    vertices = Vertices.hull(vertices);
11078                }
11079
11080                parts.push({
11081                    position: { x: x, y: y },
11082                    vertices: vertices
11083                });
11084            } else {
11085                // initialise a decomposition
11086                var concave = vertices.map(function(vertex) {
11087                    return [vertex.x, vertex.y];
11088                });
11089
11090                // vertices are concave and simple, we can decompose into parts
11091                decomp.makeCCW(concave);
11092                if (removeCollinear !== false)
11093                    decomp.removeCollinearPoints(concave, removeCollinear);
11094                if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints)
11095                    decomp.removeDuplicatePoints(concave, removeDuplicatePoints);
11096
11097                // use the quick decomposition algorithm (Bayazit)
11098                var decomposed = decomp.quickDecomp(concave);
11099
11100                // for each decomposed chunk
11101                for (i = 0; i < decomposed.length; i++) {
11102                    var chunk = decomposed[i];
11103
11104                    // convert vertices into the correct structure
11105                    var chunkVertices = chunk.map(function(vertices) {
11106                        return {
11107                            x: vertices[0],
11108                            y: vertices[1]
11109                        };
11110                    });
11111
11112                    // skip small chunks
11113                    if (minimumArea > 0 && Vertices.area(chunkVertices) < minimumArea)
11114                        continue;
11115
11116                    // create a compound part
11117                    parts.push({
11118                        position: Vertices.centre(chunkVertices),
11119                        vertices: chunkVertices
11120                    });
11121                }
11122            }
11123        }
11124
11125        // create body parts
11126        for (i = 0; i < parts.length; i++) {
11127            parts[i] = Body.create(Common.extend(parts[i], options));
11128        }
11129
11130        // flag internal edges (coincident part edges)
11131        if (flagInternal) {
11132            var coincident_max_dist = 5;
11133
11134            for (i = 0; i < parts.length; i++) {
11135                var partA = parts[i];
11136
11137                for (j = i + 1; j < parts.length; j++) {
11138                    var partB = parts[j];
11139
11140                    if (Bounds.overlaps(partA.bounds, partB.bounds)) {
11141                        var pav = partA.vertices,
11142                            pbv = partB.vertices;
11143
11144                        // iterate vertices of both parts
11145                        for (k = 0; k < partA.vertices.length; k++) {
11146                            for (z = 0; z < partB.vertices.length; z++) {
11147                                // find distances between the vertices
11148                                var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z])),
11149                                    db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length]));
11150
11151                                // if both vertices are very close, consider the edge concident (internal)
11152                                if (da < coincident_max_dist && db < coincident_max_dist) {
11153                                    pav[k].isInternal = true;
11154                                    pbv[z].isInternal = true;
11155                                }
11156                            }
11157                        }
11158
11159                    }
11160                }
11161            }
11162        }
11163
11164        if (parts.length > 1) {
11165            // create the parent body to be returned, that contains generated compound parts
11166            body = Body.create(Common.extend({ parts: parts.slice(0) }, options));
11167
11168            // offset such that body.position is at the centre off mass
11169            Body.setPosition(body, { x: x, y: y });
11170
11171            return body;
11172        } else {
11173            return parts[0];
11174        }
11175    };
11176
11177})();
11178
11179
11180/***/ }),
11181/* 13 */
11182/***/ (function(module, exports, __webpack_require__) {
11183
11184/**
11185* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.
11186*
11187* @class Detector
11188*/
11189
11190var Detector = {};
11191
11192module.exports = Detector;
11193
11194var Common = __webpack_require__(0);
11195var Collision = __webpack_require__(8);
11196
11197(function() {
11198
11199    /**
11200     * Creates a new collision detector.
11201     * @method create
11202     * @param {} options
11203     * @return {detector} A new collision detector
11204     */
11205    Detector.create = function(options) {
11206        var defaults = {
11207            bodies: [],
11208            collisions: [],
11209            pairs: null
11210        };
11211
11212        return Common.extend(defaults, options);
11213    };
11214
11215    /**
11216     * Sets the list of bodies in the detector.
11217     * @method setBodies
11218     * @param {detector} detector
11219     * @param {body[]} bodies
11220     */
11221    Detector.setBodies = function(detector, bodies) {
11222        detector.bodies = bodies.slice(0);
11223    };
11224
11225    /**
11226     * Clears the detector including its list of bodies.
11227     * @method clear
11228     * @param {detector} detector
11229     */
11230    Detector.clear = function(detector) {
11231        detector.bodies = [];
11232        detector.collisions = [];
11233    };
11234
11235    /**
11236     * Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.
11237     * 
11238     * _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.
11239     * If a specific ordering is required then apply a sort to the resulting array.
11240     * @method collisions
11241     * @param {detector} detector
11242     * @return {collision[]} collisions
11243     */
11244    Detector.collisions = function(detector) {
11245        var pairs = detector.pairs,
11246            bodies = detector.bodies,
11247            bodiesLength = bodies.length,
11248            canCollide = Detector.canCollide,
11249            collides = Collision.collides,
11250            collisions = detector.collisions,
11251            collisionIndex = 0,
11252            i,
11253            j;
11254
11255        bodies.sort(Detector._compareBoundsX);
11256
11257        for (i = 0; i < bodiesLength; i++) {
11258            var bodyA = bodies[i],
11259                boundsA = bodyA.bounds,
11260                boundXMax = bodyA.bounds.max.x,
11261                boundYMax = bodyA.bounds.max.y,
11262                boundYMin = bodyA.bounds.min.y,
11263                bodyAStatic = bodyA.isStatic || bodyA.isSleeping,
11264                partsALength = bodyA.parts.length,
11265                partsASingle = partsALength === 1;
11266
11267            for (j = i + 1; j < bodiesLength; j++) {
11268                var bodyB = bodies[j],
11269                    boundsB = bodyB.bounds;
11270
11271                if (boundsB.min.x > boundXMax) {
11272                    break;
11273                }
11274
11275                if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {
11276                    continue;
11277                }
11278
11279                if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {
11280                    continue;
11281                }
11282
11283                if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {
11284                    continue;
11285                }
11286
11287                var partsBLength = bodyB.parts.length;
11288
11289                if (partsASingle && partsBLength === 1) {
11290                    var collision = collides(bodyA, bodyB, pairs);
11291
11292                    if (collision) {
11293                        collisions[collisionIndex++] = collision;
11294                    }
11295                } else {
11296                    var partsAStart = partsALength > 1 ? 1 : 0,
11297                        partsBStart = partsBLength > 1 ? 1 : 0;
11298                    
11299                    for (var k = partsAStart; k < partsALength; k++) {
11300                        var partA = bodyA.parts[k],
11301                            boundsA = partA.bounds;
11302
11303                        for (var z = partsBStart; z < partsBLength; z++) {
11304                            var partB = bodyB.parts[z],
11305                                boundsB = partB.bounds;
11306
11307                            if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x
11308                                || boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {
11309                                continue;
11310                            }
11311
11312                            var collision = collides(partA, partB, pairs);
11313
11314                            if (collision) {
11315                                collisions[collisionIndex++] = collision;
11316                            }
11317                        }
11318                    }
11319                }
11320            }
11321        }
11322
11323        if (collisions.length !== collisionIndex) {
11324            collisions.length = collisionIndex;
11325        }
11326
11327        return collisions;
11328    };
11329
11330    /**
11331     * Returns `true` if both supplied collision filters will allow a collision to occur.
11332     * See `body.collisionFilter` for more information.
11333     * @method canCollide
11334     * @param {} filterA
11335     * @param {} filterB
11336     * @return {bool} `true` if collision can occur
11337     */
11338    Detector.canCollide = function(filterA, filterB) {
11339        if (filterA.group === filterB.group && filterA.group !== 0)
11340            return filterA.group > 0;
11341
11342        return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;
11343    };
11344
11345    /**
11346     * The comparison function used in the broadphase algorithm.
11347     * Returns the signed delta of the bodies bounds on the x-axis.
11348     * @private
11349     * @method _sortCompare
11350     * @param {body} bodyA
11351     * @param {body} bodyB
11352     * @return {number} The signed delta used for sorting
11353     */
11354    Detector._compareBoundsX = function(bodyA, bodyB) {
11355        return bodyA.bounds.min.x - bodyB.bounds.min.x;
11356    };
11357
11358    /*
11359    *
11360    *  Properties Documentation
11361    *
11362    */
11363
11364    /**
11365     * The array of `Matter.Body` between which the detector finds collisions.
11366     * 
11367     * _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.
11368     * @property bodies
11369     * @type body[]
11370     * @default []
11371     */
11372
11373    /**
11374     * The array of `Matter.Collision` found in the last call to `Detector.collisions` on this detector.
11375     * @property collisions
11376     * @type collision[]
11377     * @default []
11378     */
11379
11380    /**
11381     * Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.
11382     * @property pairs
11383     * @type {pairs|null}
11384     * @default null
11385     */
11386
11387})();
11388
11389
11390/***/ }),
11391/* 14 */
11392/***/ (function(module, exports, __webpack_require__) {
11393
11394/**
11395* The `Matter.Mouse` module contains methods for creating and manipulating mouse inputs.
11396*
11397* @class Mouse
11398*/
11399
11400var Mouse = {};
11401
11402module.exports = Mouse;
11403
11404var Common = __webpack_require__(0);
11405
11406(function() {
11407
11408    /**
11409     * Creates a mouse input.
11410     * @method create
11411     * @param {HTMLElement} element
11412     * @return {mouse} A new mouse
11413     */
11414    Mouse.create = function(element) {
11415        var mouse = {};
11416
11417        if (!element) {
11418            Common.log('Mouse.create: element was undefined, defaulting to document.body', 'warn');
11419        }
11420        
11421        mouse.element = element || document.body;
11422        mouse.absolute = { x: 0, y: 0 };
11423        mouse.position = { x: 0, y: 0 };
11424        mouse.mousedownPosition = { x: 0, y: 0 };
11425        mouse.mouseupPosition = { x: 0, y: 0 };
11426        mouse.offset = { x: 0, y: 0 };
11427        mouse.scale = { x: 1, y: 1 };
11428        mouse.wheelDelta = 0;
11429        mouse.button = -1;
11430        mouse.pixelRatio = parseInt(mouse.element.getAttribute('data-pixel-ratio'), 10) || 1;
11431
11432        mouse.sourceEvents = {
11433            mousemove: null,
11434            mousedown: null,
11435            mouseup: null,
11436            mousewheel: null
11437        };
11438        
11439        mouse.mousemove = function(event) { 
11440            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),
11441                touches = event.changedTouches;
11442
11443            if (touches) {
11444                mouse.button = 0;
11445                event.preventDefault();
11446            }
11447
11448            mouse.absolute.x = position.x;
11449            mouse.absolute.y = position.y;
11450            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
11451            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
11452            mouse.sourceEvents.mousemove = event;
11453        };
11454        
11455        mouse.mousedown = function(event) {
11456            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),
11457                touches = event.changedTouches;
11458
11459            if (touches) {
11460                mouse.button = 0;
11461                event.preventDefault();
11462            } else {
11463                mouse.button = event.button;
11464            }
11465
11466            mouse.absolute.x = position.x;
11467            mouse.absolute.y = position.y;
11468            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
11469            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
11470            mouse.mousedownPosition.x = mouse.position.x;
11471            mouse.mousedownPosition.y = mouse.position.y;
11472            mouse.sourceEvents.mousedown = event;
11473        };
11474        
11475        mouse.mouseup = function(event) {
11476            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),
11477                touches = event.changedTouches;
11478
11479            if (touches) {
11480                event.preventDefault();
11481            }
11482            
11483            mouse.button = -1;
11484            mouse.absolute.x = position.x;
11485            mouse.absolute.y = position.y;
11486            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
11487            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
11488            mouse.mouseupPosition.x = mouse.position.x;
11489            mouse.mouseupPosition.y = mouse.position.y;
11490            mouse.sourceEvents.mouseup = event;
11491        };
11492
11493        mouse.mousewheel = function(event) {
11494            mouse.wheelDelta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail));
11495            event.preventDefault();
11496            mouse.sourceEvents.mousewheel = event;
11497        };
11498
11499        Mouse.setElement(mouse, mouse.element);
11500
11501        return mouse;
11502    };
11503
11504    /**
11505     * Sets the element the mouse is bound to (and relative to).
11506     * @method setElement
11507     * @param {mouse} mouse
11508     * @param {HTMLElement} element
11509     */
11510    Mouse.setElement = function(mouse, element) {
11511        mouse.element = element;
11512
11513        element.addEventListener('mousemove', mouse.mousemove, { passive: true });
11514        element.addEventListener('mousedown', mouse.mousedown, { passive: true });
11515        element.addEventListener('mouseup', mouse.mouseup, { passive: true });
11516        
11517        element.addEventListener('wheel', mouse.mousewheel, { passive: false });
11518        
11519        element.addEventListener('touchmove', mouse.mousemove, { passive: false });
11520        element.addEventListener('touchstart', mouse.mousedown, { passive: false });
11521        element.addEventListener('touchend', mouse.mouseup, { passive: false });
11522    };
11523
11524    /**
11525     * Clears all captured source events.
11526     * @method clearSourceEvents
11527     * @param {mouse} mouse
11528     */
11529    Mouse.clearSourceEvents = function(mouse) {
11530        mouse.sourceEvents.mousemove = null;
11531        mouse.sourceEvents.mousedown = null;
11532        mouse.sourceEvents.mouseup = null;
11533        mouse.sourceEvents.mousewheel = null;
11534        mouse.wheelDelta = 0;
11535    };
11536
11537    /**
11538     * Sets the mouse position offset.
11539     * @method setOffset
11540     * @param {mouse} mouse
11541     * @param {vector} offset
11542     */
11543    Mouse.setOffset = function(mouse, offset) {
11544        mouse.offset.x = offset.x;
11545        mouse.offset.y = offset.y;
11546        mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
11547        mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
11548    };
11549
11550    /**
11551     * Sets the mouse position scale.
11552     * @method setScale
11553     * @param {mouse} mouse
11554     * @param {vector} scale
11555     */
11556    Mouse.setScale = function(mouse, scale) {
11557        mouse.scale.x = scale.x;
11558        mouse.scale.y = scale.y;
11559        mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;
11560        mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;
11561    };
11562    
11563    /**
11564     * Gets the mouse position relative to an element given a screen pixel ratio.
11565     * @method _getRelativeMousePosition
11566     * @private
11567     * @param {} event
11568     * @param {} element
11569     * @param {number} pixelRatio
11570     * @return {}
11571     */
11572    Mouse._getRelativeMousePosition = function(event, element, pixelRatio) {
11573        var elementBounds = element.getBoundingClientRect(),
11574            rootNode = (document.documentElement || document.body.parentNode || document.body),
11575            scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : rootNode.scrollLeft,
11576            scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : rootNode.scrollTop,
11577            touches = event.changedTouches,
11578            x, y;
11579        
11580        if (touches) {
11581            x = touches[0].pageX - elementBounds.left - scrollX;
11582            y = touches[0].pageY - elementBounds.top - scrollY;
11583        } else {
11584            x = event.pageX - elementBounds.left - scrollX;
11585            y = event.pageY - elementBounds.top - scrollY;
11586        }
11587
11588        return { 
11589            x: x / (element.clientWidth / (element.width || element.clientWidth) * pixelRatio),
11590            y: y / (element.clientHeight / (element.height || element.clientHeight) * pixelRatio)
11591        };
11592    };
11593
11594})();
11595
11596
11597/***/ }),
11598/* 15 */
11599/***/ (function(module, exports, __webpack_require__) {
11600
11601/**
11602* The `Matter.Plugin` module contains functions for registering and installing plugins on modules.
11603*
11604* @class Plugin
11605*/
11606
11607var Plugin = {};
11608
11609module.exports = Plugin;
11610
11611var Common = __webpack_require__(0);
11612
11613(function() {
11614
11615    Plugin._registry = {};
11616
11617    /**
11618     * Registers a plugin object so it can be resolved later by name.
11619     * @method register
11620     * @param plugin {} The plugin to register.
11621     * @return {object} The plugin.
11622     */
11623    Plugin.register = function(plugin) {
11624        if (!Plugin.isPlugin(plugin)) {
11625            Common.warn('Plugin.register:', Plugin.toString(plugin), 'does not implement all required fields.');
11626        }
11627
11628        if (plugin.name in Plugin._registry) {
11629            var registered = Plugin._registry[plugin.name],
11630                pluginVersion = Plugin.versionParse(plugin.version).number,
11631                registeredVersion = Plugin.versionParse(registered.version).number;
11632
11633            if (pluginVersion > registeredVersion) {
11634                Common.warn('Plugin.register:', Plugin.toString(registered), 'was upgraded to', Plugin.toString(plugin));
11635                Plugin._registry[plugin.name] = plugin;
11636            } else if (pluginVersion < registeredVersion) {
11637                Common.warn('Plugin.register:', Plugin.toString(registered), 'can not be downgraded to', Plugin.toString(plugin));
11638            } else if (plugin !== registered) {
11639                Common.warn('Plugin.register:', Plugin.toString(plugin), 'is already registered to different plugin object');
11640            }
11641        } else {
11642            Plugin._registry[plugin.name] = plugin;
11643        }
11644
11645        return plugin;
11646    };
11647
11648    /**
11649     * Resolves a dependency to a plugin object from the registry if it exists. 
11650     * The `dependency` may contain a version, but only the name matters when resolving.
11651     * @method resolve
11652     * @param dependency {string} The dependency.
11653     * @return {object} The plugin if resolved, otherwise `undefined`.
11654     */
11655    Plugin.resolve = function(dependency) {
11656        return Plugin._registry[Plugin.dependencyParse(dependency).name];
11657    };
11658
11659    /**
11660     * Returns a pretty printed plugin name and version.
11661     * @method toString
11662     * @param plugin {} The plugin.
11663     * @return {string} Pretty printed plugin name and version.
11664     */
11665    Plugin.toString = function(plugin) {
11666        return typeof plugin === 'string' ? plugin : (plugin.name || 'anonymous') + '@' + (plugin.version || plugin.range || '0.0.0');
11667    };
11668
11669    /**
11670     * Returns `true` if the object meets the minimum standard to be considered a plugin.
11671     * This means it must define the following properties:
11672     * - `name`
11673     * - `version`
11674     * - `install`
11675     * @method isPlugin
11676     * @param obj {} The obj to test.
11677     * @return {boolean} `true` if the object can be considered a plugin otherwise `false`.
11678     */
11679    Plugin.isPlugin = function(obj) {
11680        return obj && obj.name && obj.version && obj.install;
11681    };
11682
11683    /**
11684     * Returns `true` if a plugin with the given `name` been installed on `module`.
11685     * @method isUsed
11686     * @param module {} The module.
11687     * @param name {string} The plugin name.
11688     * @return {boolean} `true` if a plugin with the given `name` been installed on `module`, otherwise `false`.
11689     */
11690    Plugin.isUsed = function(module, name) {
11691        return module.used.indexOf(name) > -1;
11692    };
11693
11694    /**
11695     * Returns `true` if `plugin.for` is applicable to `module` by comparing against `module.name` and `module.version`.
11696     * If `plugin.for` is not specified then it is assumed to be applicable.
11697     * The value of `plugin.for` is a string of the format `'module-name'` or `'module-name@version'`.
11698     * @method isFor
11699     * @param plugin {} The plugin.
11700     * @param module {} The module.
11701     * @return {boolean} `true` if `plugin.for` is applicable to `module`, otherwise `false`.
11702     */
11703    Plugin.isFor = function(plugin, module) {
11704        var parsed = plugin.for && Plugin.dependencyParse(plugin.for);
11705        return !plugin.for || (module.name === parsed.name && Plugin.versionSatisfies(module.version, parsed.range));
11706    };
11707
11708    /**
11709     * Installs the plugins by calling `plugin.install` on each plugin specified in `plugins` if passed, otherwise `module.uses`.
11710     * For installing plugins on `Matter` see the convenience function `Matter.use`.
11711     * Plugins may be specified either by their name or a reference to the plugin object.
11712     * Plugins themselves may specify further dependencies, but each plugin is installed only once.
11713     * Order is important, a topological sort is performed to find the best resulting order of installation.
11714     * This sorting attempts to satisfy every dependency's requested ordering, but may not be exact in all cases.
11715     * This function logs the resulting status of each dependency in the console, along with any warnings.
11716     * - A green tick ✅ indicates a dependency was resolved and installed.
11717     * - An orange diamond 🔶 indicates a dependency was resolved but a warning was thrown for it or one if its dependencies.
11718     * - A red cross ❌ indicates a dependency could not be resolved.
11719     * Avoid calling this function multiple times on the same module unless you intend to manually control installation order.
11720     * @method use
11721     * @param module {} The module install plugins on.
11722     * @param [plugins=module.uses] {} The plugins to install on module (optional, defaults to `module.uses`).
11723     */
11724    Plugin.use = function(module, plugins) {
11725        module.uses = (module.uses || []).concat(plugins || []);
11726
11727        if (module.uses.length === 0) {
11728            Common.warn('Plugin.use:', Plugin.toString(module), 'does not specify any dependencies to install.');
11729            return;
11730        }
11731
11732        var dependencies = Plugin.dependencies(module),
11733            sortedDependencies = Common.topologicalSort(dependencies),
11734            status = [];
11735
11736        for (var i = 0; i < sortedDependencies.length; i += 1) {
11737            if (sortedDependencies[i] === module.name) {
11738                continue;
11739            }
11740
11741            var plugin = Plugin.resolve(sortedDependencies[i]);
11742
11743            if (!plugin) {
11744                status.push('❌ ' + sortedDependencies[i]);
11745                continue;
11746            }
11747
11748            if (Plugin.isUsed(module, plugin.name)) {
11749                continue;
11750            }
11751
11752            if (!Plugin.isFor(plugin, module)) {
11753                Common.warn('Plugin.use:', Plugin.toString(plugin), 'is for', plugin.for, 'but installed on', Plugin.toString(module) + '.');
11754                plugin._warned = true;
11755            }
11756
11757            if (plugin.install) {
11758                plugin.install(module);
11759            } else {
11760                Common.warn('Plugin.use:', Plugin.toString(plugin), 'does not specify an install function.');
11761                plugin._warned = true;
11762            }
11763
11764            if (plugin._warned) {
11765                status.push('🔶 ' + Plugin.toString(plugin));
11766                delete plugin._warned;
11767            } else {
11768                status.push('✅ ' + Plugin.toString(plugin));
11769            }
11770
11771            module.used.push(plugin.name);
11772        }
11773
11774        if (status.length > 0) {
11775            Common.info(status.join('  '));
11776        }
11777    };
11778
11779    /**
11780     * Recursively finds all of a module's dependencies and returns a flat dependency graph.
11781     * @method dependencies
11782     * @param module {} The module.
11783     * @return {object} A dependency graph.
11784     */
11785    Plugin.dependencies = function(module, tracked) {
11786        var parsedBase = Plugin.dependencyParse(module),
11787            name = parsedBase.name;
11788
11789        tracked = tracked || {};
11790
11791        if (name in tracked) {
11792            return;
11793        }
11794
11795        module = Plugin.resolve(module) || module;
11796
11797        tracked[name] = Common.map(module.uses || [], function(dependency) {
11798            if (Plugin.isPlugin(dependency)) {
11799                Plugin.register(dependency);
11800            }
11801
11802            var parsed = Plugin.dependencyParse(dependency),
11803                resolved = Plugin.resolve(dependency);
11804
11805            if (resolved && !Plugin.versionSatisfies(resolved.version, parsed.range)) {
11806                Common.warn(
11807                    'Plugin.dependencies:', Plugin.toString(resolved), 'does not satisfy',
11808                    Plugin.toString(parsed), 'used by', Plugin.toString(parsedBase) + '.'
11809                );
11810
11811                resolved._warned = true;
11812                module._warned = true;
11813            } else if (!resolved) {
11814                Common.warn(
11815                    'Plugin.dependencies:', Plugin.toString(dependency), 'used by',
11816                    Plugin.toString(parsedBase), 'could not be resolved.'
11817                );
11818
11819                module._warned = true;
11820            }
11821
11822            return parsed.name;
11823        });
11824
11825        for (var i = 0; i < tracked[name].length; i += 1) {
11826            Plugin.dependencies(tracked[name][i], tracked);
11827        }
11828
11829        return tracked;
11830    };
11831
11832    /**
11833     * Parses a dependency string into its components.
11834     * The `dependency` is a string of the format `'module-name'` or `'module-name@version'`.
11835     * See documentation for `Plugin.versionParse` for a description of the format.
11836     * This function can also handle dependencies that are already resolved (e.g. a module object).
11837     * @method dependencyParse
11838     * @param dependency {string} The dependency of the format `'module-name'` or `'module-name@version'`.
11839     * @return {object} The dependency parsed into its components.
11840     */
11841    Plugin.dependencyParse = function(dependency) {
11842        if (Common.isString(dependency)) {
11843            var pattern = /^[\w-]+(@(\*|[\^~]?\d+\.\d+\.\d+(-[0-9A-Za-z-+]+)?))?$/;
11844
11845            if (!pattern.test(dependency)) {
11846                Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.');
11847            }
11848
11849            return {
11850                name: dependency.split('@')[0],
11851                range: dependency.split('@')[1] || '*'
11852            };
11853        }
11854
11855        return {
11856            name: dependency.name,
11857            range: dependency.range || dependency.version
11858        };
11859    };
11860
11861    /**
11862     * Parses a version string into its components.  
11863     * Versions are strictly of the format `x.y.z` (as in [semver](http://semver.org/)).
11864     * Versions may optionally have a prerelease tag in the format `x.y.z-alpha`.
11865     * Ranges are a strict subset of [npm ranges](https://docs.npmjs.com/misc/semver#advanced-range-syntax).
11866     * Only the following range types are supported:
11867     * - Tilde ranges e.g. `~1.2.3`
11868     * - Caret ranges e.g. `^1.2.3`
11869     * - Greater than ranges e.g. `>1.2.3`
11870     * - Greater than or equal ranges e.g. `>=1.2.3`
11871     * - Exact version e.g. `1.2.3`
11872     * - Any version `*`
11873     * @method versionParse
11874     * @param range {string} The version string.
11875     * @return {object} The version range parsed into its components.
11876     */
11877    Plugin.versionParse = function(range) {
11878        var pattern = /^(\*)|(\^|~|>=|>)?\s*((\d+)\.(\d+)\.(\d+))(-[0-9A-Za-z-+]+)?$/;
11879
11880        if (!pattern.test(range)) {
11881            Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.');
11882        }
11883
11884        var parts = pattern.exec(range);
11885        var major = Number(parts[4]);
11886        var minor = Number(parts[5]);
11887        var patch = Number(parts[6]);
11888
11889        return {
11890            isRange: Boolean(parts[1] || parts[2]),
11891            version: parts[3],
11892            range: range,
11893            operator: parts[1] || parts[2] || '',
11894            major: major,
11895            minor: minor,
11896            patch: patch,
11897            parts: [major, minor, patch],
11898            prerelease: parts[7],
11899            number: major * 1e8 + minor * 1e4 + patch
11900        };
11901    };
11902
11903    /**
11904     * Returns `true` if `version` satisfies the given `range`.
11905     * See documentation for `Plugin.versionParse` for a description of the format.
11906     * If a version or range is not specified, then any version (`*`) is assumed to satisfy.
11907     * @method versionSatisfies
11908     * @param version {string} The version string.
11909     * @param range {string} The range string.
11910     * @return {boolean} `true` if `version` satisfies `range`, otherwise `false`.
11911     */
11912    Plugin.versionSatisfies = function(version, range) {
11913        range = range || '*';
11914
11915        var r = Plugin.versionParse(range),
11916            v = Plugin.versionParse(version);
11917
11918        if (r.isRange) {
11919            if (r.operator === '*' || version === '*') {
11920                return true;
11921            }
11922
11923            if (r.operator === '>') {
11924                return v.number > r.number;
11925            }
11926
11927            if (r.operator === '>=') {
11928                return v.number >= r.number;
11929            }
11930
11931            if (r.operator === '~') {
11932                return v.major === r.major && v.minor === r.minor && v.patch >= r.patch;
11933            }
11934
11935            if (r.operator === '^') {
11936                if (r.major > 0) {
11937                    return v.major === r.major && v.number >= r.number;
11938                }
11939
11940                if (r.minor > 0) {
11941                    return v.minor === r.minor && v.patch >= r.patch;
11942                }
11943
11944                return v.patch === r.patch;
11945            }
11946        }
11947
11948        return version === range || version === '*';
11949    };
11950
11951})();
11952
11953
11954/***/ }),
11955/* 16 */
11956/***/ (function(module, exports) {
11957
11958/**
11959* The `Matter.Contact` module contains methods for creating and manipulating collision contacts.
11960*
11961* @class Contact
11962*/
11963
11964var Contact = {};
11965
11966module.exports = Contact;
11967
11968(function() {
11969
11970    /**
11971     * Creates a new contact.
11972     * @method create
11973     * @param {vertex} [vertex]
11974     * @return {contact} A new contact
11975     */
11976    Contact.create = function(vertex) {
11977        return {
11978            vertex: vertex,
11979            normalImpulse: 0,
11980            tangentImpulse: 0
11981        };
11982    };
11983
11984})();
11985
11986
11987/***/ }),
11988/* 17 */
11989/***/ (function(module, exports, __webpack_require__) {
11990
11991/**
11992* The `Matter.Engine` module contains methods for creating and manipulating engines.
11993* An engine is a controller that manages updating the simulation of the world.
11994* See `Matter.Runner` for an optional game loop utility.
11995*
11996* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
11997*
11998* @class Engine
11999*/
12000
12001var Engine = {};
12002
12003module.exports = Engine;
12004
12005var Sleeping = __webpack_require__(7);
12006var Resolver = __webpack_require__(18);
12007var Detector = __webpack_require__(13);
12008var Pairs = __webpack_require__(19);
12009var Events = __webpack_require__(5);
12010var Composite = __webpack_require__(6);
12011var Constraint = __webpack_require__(10);
12012var Common = __webpack_require__(0);
12013var Body = __webpack_require__(4);
12014
12015(function() {
12016
12017    Engine._deltaMax = 1000 / 60;
12018
12019    /**
12020     * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults.
12021     * All properties have default values, and many are pre-calculated automatically based on other properties.
12022     * See the properties section below for detailed information on what you can pass via the `options` object.
12023     * @method create
12024     * @param {object} [options]
12025     * @return {engine} engine
12026     */
12027    Engine.create = function(options) {
12028        options = options || {};
12029
12030        var defaults = {
12031            positionIterations: 6,
12032            velocityIterations: 4,
12033            constraintIterations: 2,
12034            enableSleeping: false,
12035            events: [],
12036            plugin: {},
12037            gravity: {
12038                x: 0,
12039                y: 1,
12040                scale: 0.001
12041            },
12042            timing: {
12043                timestamp: 0,
12044                timeScale: 1,
12045                lastDelta: 0,
12046                lastElapsed: 0,
12047                lastUpdatesPerFrame: 0
12048            }
12049        };
12050
12051        var engine = Common.extend(defaults, options);
12052
12053        engine.world = options.world || Composite.create({ label: 'World' });
12054        engine.pairs = options.pairs || Pairs.create();
12055        engine.detector = options.detector || Detector.create();
12056        engine.detector.pairs = engine.pairs;
12057
12058        // for temporary back compatibility only
12059        engine.grid = { buckets: [] };
12060        engine.world.gravity = engine.gravity;
12061        engine.broadphase = engine.grid;
12062        engine.metrics = {};
12063        
12064        return engine;
12065    };
12066
12067    /**
12068     * Moves the simulation forward in time by `delta` milliseconds.
12069     * Triggers `beforeUpdate`, `beforeSolve` and `afterUpdate` events.
12070     * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events.
12071     * @method update
12072     * @param {engine} engine
12073     * @param {number} [delta=16.666]
12074     */
12075    Engine.update = function(engine, delta) {
12076        var startTime = Common.now();
12077
12078        var world = engine.world,
12079            detector = engine.detector,
12080            pairs = engine.pairs,
12081            timing = engine.timing,
12082            timestamp = timing.timestamp,
12083            i;
12084
12085        // warn if high delta
12086        if (delta > Engine._deltaMax) {
12087            Common.warnOnce(
12088                'Matter.Engine.update: delta argument is recommended to be less than or equal to', Engine._deltaMax.toFixed(3), 'ms.'
12089            );
12090        }
12091
12092        delta = typeof delta !== 'undefined' ? delta : Common._baseDelta;
12093        delta *= timing.timeScale;
12094
12095        // increment timestamp
12096        timing.timestamp += delta;
12097        timing.lastDelta = delta;
12098
12099        // create an event object
12100        var event = {
12101            timestamp: timing.timestamp,
12102            delta: delta
12103        };
12104
12105        Events.trigger(engine, 'beforeUpdate', event);
12106
12107        // get all bodies and all constraints in the world
12108        var allBodies = Composite.allBodies(world),
12109            allConstraints = Composite.allConstraints(world);
12110
12111        // if the world has changed
12112        if (world.isModified) {
12113            // update the detector bodies
12114            Detector.setBodies(detector, allBodies);
12115
12116            // reset all composite modified flags
12117            Composite.setModified(world, false, false, true);
12118        }
12119
12120        // update sleeping if enabled
12121        if (engine.enableSleeping)
12122            Sleeping.update(allBodies, delta);
12123
12124        // apply gravity to all bodies
12125        Engine._bodiesApplyGravity(allBodies, engine.gravity);
12126
12127        // update all body position and rotation by integration
12128        if (delta > 0) {
12129            Engine._bodiesUpdate(allBodies, delta);
12130        }
12131
12132        Events.trigger(engine, 'beforeSolve', event);
12133
12134        // update all constraints (first pass)
12135        Constraint.preSolveAll(allBodies);
12136        for (i = 0; i < engine.constraintIterations; i++) {
12137            Constraint.solveAll(allConstraints, delta);
12138        }
12139        Constraint.postSolveAll(allBodies);
12140
12141        // find all collisions
12142        var collisions = Detector.collisions(detector);
12143
12144        // update collision pairs
12145        Pairs.update(pairs, collisions, timestamp);
12146
12147        // wake up bodies involved in collisions
12148        if (engine.enableSleeping)
12149            Sleeping.afterCollisions(pairs.list);
12150
12151        // trigger collision events
12152        if (pairs.collisionStart.length > 0) {
12153            Events.trigger(engine, 'collisionStart', { 
12154                pairs: pairs.collisionStart,
12155                timestamp: timing.timestamp,
12156                delta: delta
12157            });
12158        }
12159
12160        // iteratively resolve position between collisions
12161        var positionDamping = Common.clamp(20 / engine.positionIterations, 0, 1);
12162        
12163        Resolver.preSolvePosition(pairs.list);
12164        for (i = 0; i < engine.positionIterations; i++) {
12165            Resolver.solvePosition(pairs.list, delta, positionDamping);
12166        }
12167        Resolver.postSolvePosition(allBodies);
12168
12169        // update all constraints (second pass)
12170        Constraint.preSolveAll(allBodies);
12171        for (i = 0; i < engine.constraintIterations; i++) {
12172            Constraint.solveAll(allConstraints, delta);
12173        }
12174        Constraint.postSolveAll(allBodies);
12175
12176        // iteratively resolve velocity between collisions
12177        Resolver.preSolveVelocity(pairs.list);
12178        for (i = 0; i < engine.velocityIterations; i++) {
12179            Resolver.solveVelocity(pairs.list, delta);
12180        }
12181
12182        // update body speed and velocity properties
12183        Engine._bodiesUpdateVelocities(allBodies);
12184
12185        // trigger collision events
12186        if (pairs.collisionActive.length > 0) {
12187            Events.trigger(engine, 'collisionActive', { 
12188                pairs: pairs.collisionActive, 
12189                timestamp: timing.timestamp,
12190                delta: delta
12191            });
12192        }
12193
12194        if (pairs.collisionEnd.length > 0) {
12195            Events.trigger(engine, 'collisionEnd', {
12196                pairs: pairs.collisionEnd,
12197                timestamp: timing.timestamp,
12198                delta: delta
12199            });
12200        }
12201
12202        // clear force buffers
12203        Engine._bodiesClearForces(allBodies);
12204
12205        Events.trigger(engine, 'afterUpdate', event);
12206
12207        // log the time elapsed computing this update
12208        engine.timing.lastElapsed = Common.now() - startTime;
12209
12210        return engine;
12211    };
12212    
12213    /**
12214     * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`.
12215     * @method merge
12216     * @param {engine} engineA
12217     * @param {engine} engineB
12218     */
12219    Engine.merge = function(engineA, engineB) {
12220        Common.extend(engineA, engineB);
12221        
12222        if (engineB.world) {
12223            engineA.world = engineB.world;
12224
12225            Engine.clear(engineA);
12226
12227            var bodies = Composite.allBodies(engineA.world);
12228
12229            for (var i = 0; i < bodies.length; i++) {
12230                var body = bodies[i];
12231                Sleeping.set(body, false);
12232                body.id = Common.nextId();
12233            }
12234        }
12235    };
12236
12237    /**
12238     * Clears the engine pairs and detector.
12239     * @method clear
12240     * @param {engine} engine
12241     */
12242    Engine.clear = function(engine) {
12243        Pairs.clear(engine.pairs);
12244        Detector.clear(engine.detector);
12245    };
12246
12247    /**
12248     * Zeroes the `body.force` and `body.torque` force buffers.
12249     * @method _bodiesClearForces
12250     * @private
12251     * @param {body[]} bodies
12252     */
12253    Engine._bodiesClearForces = function(bodies) {
12254        var bodiesLength = bodies.length;
12255
12256        for (var i = 0; i < bodiesLength; i++) {
12257            var body = bodies[i];
12258
12259            // reset force buffers
12260            body.force.x = 0;
12261            body.force.y = 0;
12262            body.torque = 0;
12263        }
12264    };
12265
12266    /**
12267     * Applies gravitational acceleration to all `bodies`.
12268     * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet.
12269     * 
12270     * @method _bodiesApplyGravity
12271     * @private
12272     * @param {body[]} bodies
12273     * @param {vector} gravity
12274     */
12275    Engine._bodiesApplyGravity = function(bodies, gravity) {
12276        var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001,
12277            bodiesLength = bodies.length;
12278
12279        if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) {
12280            return;
12281        }
12282        
12283        for (var i = 0; i < bodiesLength; i++) {
12284            var body = bodies[i];
12285
12286            if (body.isStatic || body.isSleeping)
12287                continue;
12288
12289            // add the resultant force of gravity
12290            body.force.y += body.mass * gravity.y * gravityScale;
12291            body.force.x += body.mass * gravity.x * gravityScale;
12292        }
12293    };
12294
12295    /**
12296     * Applies `Body.update` to all given `bodies`.
12297     * @method _bodiesUpdate
12298     * @private
12299     * @param {body[]} bodies
12300     * @param {number} delta The amount of time elapsed between updates
12301     */
12302    Engine._bodiesUpdate = function(bodies, delta) {
12303        var bodiesLength = bodies.length;
12304
12305        for (var i = 0; i < bodiesLength; i++) {
12306            var body = bodies[i];
12307
12308            if (body.isStatic || body.isSleeping)
12309                continue;
12310
12311            Body.update(body, delta);
12312        }
12313    };
12314
12315    /**
12316     * Applies `Body.updateVelocities` to all given `bodies`.
12317     * @method _bodiesUpdateVelocities
12318     * @private
12319     * @param {body[]} bodies
12320     */
12321    Engine._bodiesUpdateVelocities = function(bodies) {
12322        var bodiesLength = bodies.length;
12323
12324        for (var i = 0; i < bodiesLength; i++) {
12325            Body.updateVelocities(bodies[i]);
12326        }
12327    };
12328
12329    /**
12330     * A deprecated alias for `Runner.run`, use `Matter.Runner.run(engine)` instead and see `Matter.Runner` for more information.
12331     * @deprecated use Matter.Runner.run(engine) instead
12332     * @method run
12333     * @param {engine} engine
12334     */
12335
12336    /**
12337    * Fired just before an update
12338    *
12339    * @event beforeUpdate
12340    * @param {object} event An event object
12341    * @param {number} event.timestamp The engine.timing.timestamp of the event
12342    * @param {number} event.delta The delta time in milliseconds value used in the update
12343    * @param {engine} event.source The source object of the event
12344    * @param {string} event.name The name of the event
12345    */
12346
12347    /**
12348    * Fired after bodies updated based on their velocity and forces, but before any collision detection, constraints and resolving etc.
12349    *
12350    * @event beforeSolve
12351    * @param {object} event An event object
12352    * @param {number} event.timestamp The engine.timing.timestamp of the event
12353    * @param {number} event.delta The delta time in milliseconds value used in the update
12354    * @param {engine} event.source The source object of the event
12355    * @param {string} event.name The name of the event
12356    */
12357
12358    /**
12359    * Fired after engine update and all collision events
12360    *
12361    * @event afterUpdate
12362    * @param {object} event An event object
12363    * @param {number} event.timestamp The engine.timing.timestamp of the event
12364    * @param {number} event.delta The delta time in milliseconds value used in the update
12365    * @param {engine} event.source The source object of the event
12366    * @param {string} event.name The name of the event
12367    */
12368
12369    /**
12370    * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)
12371    *
12372    * @event collisionStart
12373    * @param {object} event An event object
12374    * @param {pair[]} event.pairs List of affected pairs
12375    * @param {number} event.timestamp The engine.timing.timestamp of the event
12376    * @param {number} event.delta The delta time in milliseconds value used in the update
12377    * @param {engine} event.source The source object of the event
12378    * @param {string} event.name The name of the event
12379    */
12380
12381    /**
12382    * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)
12383    *
12384    * @event collisionActive
12385    * @param {object} event An event object
12386    * @param {pair[]} event.pairs List of affected pairs
12387    * @param {number} event.timestamp The engine.timing.timestamp of the event
12388    * @param {number} event.delta The delta time in milliseconds value used in the update
12389    * @param {engine} event.source The source object of the event
12390    * @param {string} event.name The name of the event
12391    */
12392
12393    /**
12394    * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)
12395    *
12396    * @event collisionEnd
12397    * @param {object} event An event object
12398    * @param {pair[]} event.pairs List of affected pairs
12399    * @param {number} event.timestamp The engine.timing.timestamp of the event
12400    * @param {number} event.delta The delta time in milliseconds value used in the update
12401    * @param {engine} event.source The source object of the event
12402    * @param {string} event.name The name of the event
12403    */
12404
12405    /*
12406    *
12407    *  Properties Documentation
12408    *
12409    */
12410
12411    /**
12412     * An integer `Number` that specifies the number of position iterations to perform each update.
12413     * The higher the value, the higher quality the simulation will be at the expense of performance.
12414     *
12415     * @property positionIterations
12416     * @type number
12417     * @default 6
12418     */
12419
12420    /**
12421     * An integer `Number` that specifies the number of velocity iterations to perform each update.
12422     * The higher the value, the higher quality the simulation will be at the expense of performance.
12423     *
12424     * @property velocityIterations
12425     * @type number
12426     * @default 4
12427     */
12428
12429    /**
12430     * An integer `Number` that specifies the number of constraint iterations to perform each update.
12431     * The higher the value, the higher quality the simulation will be at the expense of performance.
12432     * The default value of `2` is usually very adequate.
12433     *
12434     * @property constraintIterations
12435     * @type number
12436     * @default 2
12437     */
12438
12439    /**
12440     * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module.
12441     * Sleeping can improve stability and performance, but often at the expense of accuracy.
12442     *
12443     * @property enableSleeping
12444     * @type boolean
12445     * @default false
12446     */
12447
12448    /**
12449     * An `Object` containing properties regarding the timing systems of the engine. 
12450     *
12451     * @property timing
12452     * @type object
12453     */
12454
12455    /**
12456     * A `Number` that specifies the global scaling factor of time for all bodies.
12457     * A value of `0` freezes the simulation.
12458     * A value of `0.1` gives a slow-motion effect.
12459     * A value of `1.2` gives a speed-up effect.
12460     *
12461     * @property timing.timeScale
12462     * @type number
12463     * @default 1
12464     */
12465
12466    /**
12467     * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. 
12468     * It is incremented on every `Engine.update` by the given `delta` argument. 
12469     * 
12470     * @property timing.timestamp
12471     * @type number
12472     * @default 0
12473     */
12474
12475    /**
12476     * A `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds.
12477     * It is updated by timing from the start of the last `Engine.update` call until it ends.
12478     *
12479     * This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update.
12480     * 
12481     * @property timing.lastElapsed
12482     * @type number
12483     * @default 0
12484     */
12485
12486    /**
12487     * A `Number` that represents the `delta` value used in the last engine update.
12488     * 
12489     * @property timing.lastDelta
12490     * @type number
12491     * @default 0
12492     */
12493
12494    /**
12495     * A `Matter.Detector` instance.
12496     *
12497     * @property detector
12498     * @type detector
12499     * @default a Matter.Detector instance
12500     */
12501
12502    /**
12503     * A `Matter.Grid` instance.
12504     *
12505     * @deprecated replaced by `engine.detector`
12506     * @property grid
12507     * @type grid
12508     * @default a Matter.Grid instance
12509     */
12510
12511    /**
12512     * Replaced by and now alias for `engine.grid`.
12513     *
12514     * @deprecated replaced by `engine.detector`
12515     * @property broadphase
12516     * @type grid
12517     * @default a Matter.Grid instance
12518     */
12519
12520    /**
12521     * The root `Matter.Composite` instance that will contain all bodies, constraints and other composites to be simulated by this engine.
12522     *
12523     * @property world
12524     * @type composite
12525     * @default a Matter.Composite instance
12526     */
12527
12528    /**
12529     * An object reserved for storing plugin-specific properties.
12530     *
12531     * @property plugin
12532     * @type {}
12533     */
12534
12535    /**
12536     * An optional gravitational acceleration applied to all bodies in `engine.world` on every update.
12537     * 
12538     * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet. For gravity in other contexts, disable this and apply forces as needed.
12539     * 
12540     * To disable set the `scale` component to `0`.
12541     * 
12542     * This is split into three components for ease of use:  
12543     * a normalised direction (`x` and `y`) and magnitude (`scale`).
12544     *
12545     * @property gravity
12546     * @type object
12547     */
12548
12549    /**
12550     * The gravitational direction normal `x` component, to be multiplied by `gravity.scale`.
12551     * 
12552     * @property gravity.x
12553     * @type object
12554     * @default 0
12555     */
12556
12557    /**
12558     * The gravitational direction normal `y` component, to be multiplied by `gravity.scale`.
12559     *
12560     * @property gravity.y
12561     * @type object
12562     * @default 1
12563     */
12564
12565    /**
12566     * The magnitude of the gravitational acceleration.
12567     * 
12568     * @property gravity.scale
12569     * @type object
12570     * @default 0.001
12571     */
12572
12573})();
12574
12575
12576/***/ }),
12577/* 18 */
12578/***/ (function(module, exports, __webpack_require__) {
12579
12580/**
12581* The `Matter.Resolver` module contains methods for resolving collision pairs.
12582*
12583* @class Resolver
12584*/
12585
12586var Resolver = {};
12587
12588module.exports = Resolver;
12589
12590var Vertices = __webpack_require__(3);
12591var Common = __webpack_require__(0);
12592var Bounds = __webpack_require__(1);
12593
12594(function() {
12595
12596    Resolver._restingThresh = 2;
12597    Resolver._restingThreshTangent = Math.sqrt(6);
12598    Resolver._positionDampen = 0.9;
12599    Resolver._positionWarming = 0.8;
12600    Resolver._frictionNormalMultiplier = 5;
12601    Resolver._frictionMaxStatic = Number.MAX_VALUE;
12602
12603    /**
12604     * Prepare pairs for position solving.
12605     * @method preSolvePosition
12606     * @param {pair[]} pairs
12607     */
12608    Resolver.preSolvePosition = function(pairs) {
12609        var i,
12610            pair,
12611            contactCount,
12612            pairsLength = pairs.length;
12613
12614        // find total contacts on each body
12615        for (i = 0; i < pairsLength; i++) {
12616            pair = pairs[i];
12617            
12618            if (!pair.isActive)
12619                continue;
12620            
12621            contactCount = pair.contactCount;
12622            pair.collision.parentA.totalContacts += contactCount;
12623            pair.collision.parentB.totalContacts += contactCount;
12624        }
12625    };
12626
12627    /**
12628     * Find a solution for pair positions.
12629     * @method solvePosition
12630     * @param {pair[]} pairs
12631     * @param {number} delta
12632     * @param {number} [damping=1]
12633     */
12634    Resolver.solvePosition = function(pairs, delta, damping) {
12635        var i,
12636            pair,
12637            collision,
12638            bodyA,
12639            bodyB,
12640            normal,
12641            contactShare,
12642            positionImpulse,
12643            positionDampen = Resolver._positionDampen * (damping || 1),
12644            slopDampen = Common.clamp(delta / Common._baseDelta, 0, 1),
12645            pairsLength = pairs.length;
12646
12647        // find impulses required to resolve penetration
12648        for (i = 0; i < pairsLength; i++) {
12649            pair = pairs[i];
12650            
12651            if (!pair.isActive || pair.isSensor)
12652                continue;
12653
12654            collision = pair.collision;
12655            bodyA = collision.parentA;
12656            bodyB = collision.parentB;
12657            normal = collision.normal;
12658
12659            // get current separation between body edges involved in collision
12660            pair.separation = 
12661                collision.depth + normal.x * (bodyB.positionImpulse.x - bodyA.positionImpulse.x)
12662                + normal.y * (bodyB.positionImpulse.y - bodyA.positionImpulse.y);
12663        }
12664        
12665        for (i = 0; i < pairsLength; i++) {
12666            pair = pairs[i];
12667
12668            if (!pair.isActive || pair.isSensor)
12669                continue;
12670            
12671            collision = pair.collision;
12672            bodyA = collision.parentA;
12673            bodyB = collision.parentB;
12674            normal = collision.normal;
12675            positionImpulse = pair.separation - pair.slop * slopDampen;
12676
12677            if (bodyA.isStatic || bodyB.isStatic)
12678                positionImpulse *= 2;
12679            
12680            if (!(bodyA.isStatic || bodyA.isSleeping)) {
12681                contactShare = positionDampen / bodyA.totalContacts;
12682                bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;
12683                bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;
12684            }
12685
12686            if (!(bodyB.isStatic || bodyB.isSleeping)) {
12687                contactShare = positionDampen / bodyB.totalContacts;
12688                bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;
12689                bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;
12690            }
12691        }
12692    };
12693
12694    /**
12695     * Apply position resolution.
12696     * @method postSolvePosition
12697     * @param {body[]} bodies
12698     */
12699    Resolver.postSolvePosition = function(bodies) {
12700        var positionWarming = Resolver._positionWarming,
12701            bodiesLength = bodies.length,
12702            verticesTranslate = Vertices.translate,
12703            boundsUpdate = Bounds.update;
12704
12705        for (var i = 0; i < bodiesLength; i++) {
12706            var body = bodies[i],
12707                positionImpulse = body.positionImpulse,
12708                positionImpulseX = positionImpulse.x,
12709                positionImpulseY = positionImpulse.y,
12710                velocity = body.velocity;
12711
12712            // reset contact count
12713            body.totalContacts = 0;
12714
12715            if (positionImpulseX !== 0 || positionImpulseY !== 0) {
12716                // update body geometry
12717                for (var j = 0; j < body.parts.length; j++) {
12718                    var part = body.parts[j];
12719                    verticesTranslate(part.vertices, positionImpulse);
12720                    boundsUpdate(part.bounds, part.vertices, velocity);
12721                    part.position.x += positionImpulseX;
12722                    part.position.y += positionImpulseY;
12723                }
12724
12725                // move the body without changing velocity
12726                body.positionPrev.x += positionImpulseX;
12727                body.positionPrev.y += positionImpulseY;
12728
12729                if (positionImpulseX * velocity.x + positionImpulseY * velocity.y < 0) {
12730                    // reset cached impulse if the body has velocity along it
12731                    positionImpulse.x = 0;
12732                    positionImpulse.y = 0;
12733                } else {
12734                    // warm the next iteration
12735                    positionImpulse.x *= positionWarming;
12736                    positionImpulse.y *= positionWarming;
12737                }
12738            }
12739        }
12740    };
12741
12742    /**
12743     * Prepare pairs for velocity solving.
12744     * @method preSolveVelocity
12745     * @param {pair[]} pairs
12746     */
12747    Resolver.preSolveVelocity = function(pairs) {
12748        var pairsLength = pairs.length,
12749            i,
12750            j;
12751        
12752        for (i = 0; i < pairsLength; i++) {
12753            var pair = pairs[i];
12754            
12755            if (!pair.isActive || pair.isSensor)
12756                continue;
12757            
12758            var contacts = pair.contacts,
12759                contactCount = pair.contactCount,
12760                collision = pair.collision,
12761                bodyA = collision.parentA,
12762                bodyB = collision.parentB,
12763                normal = collision.normal,
12764                tangent = collision.tangent;
12765    
12766            // resolve each contact
12767            for (j = 0; j < contactCount; j++) {
12768                var contact = contacts[j],
12769                    contactVertex = contact.vertex,
12770                    normalImpulse = contact.normalImpulse,
12771                    tangentImpulse = contact.tangentImpulse;
12772    
12773                if (normalImpulse !== 0 || tangentImpulse !== 0) {
12774                    // total impulse from contact
12775                    var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse,
12776                        impulseY = normal.y * normalImpulse + tangent.y * tangentImpulse;
12777                    
12778                    // apply impulse from contact
12779                    if (!(bodyA.isStatic || bodyA.isSleeping)) {
12780                        bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
12781                        bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
12782                        bodyA.anglePrev += bodyA.inverseInertia * (
12783                            (contactVertex.x - bodyA.position.x) * impulseY
12784                            - (contactVertex.y - bodyA.position.y) * impulseX
12785                        );
12786                    }
12787    
12788                    if (!(bodyB.isStatic || bodyB.isSleeping)) {
12789                        bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
12790                        bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
12791                        bodyB.anglePrev -= bodyB.inverseInertia * (
12792                            (contactVertex.x - bodyB.position.x) * impulseY 
12793                            - (contactVertex.y - bodyB.position.y) * impulseX
12794                        );
12795                    }
12796                }
12797            }
12798        }
12799    };
12800
12801    /**
12802     * Find a solution for pair velocities.
12803     * @method solveVelocity
12804     * @param {pair[]} pairs
12805     * @param {number} delta
12806     */
12807    Resolver.solveVelocity = function(pairs, delta) {
12808        var timeScale = delta / Common._baseDelta,
12809            timeScaleSquared = timeScale * timeScale,
12810            timeScaleCubed = timeScaleSquared * timeScale,
12811            restingThresh = -Resolver._restingThresh * timeScale,
12812            restingThreshTangent = Resolver._restingThreshTangent,
12813            frictionNormalMultiplier = Resolver._frictionNormalMultiplier * timeScale,
12814            frictionMaxStatic = Resolver._frictionMaxStatic,
12815            pairsLength = pairs.length,
12816            tangentImpulse,
12817            maxFriction,
12818            i,
12819            j;
12820
12821        for (i = 0; i < pairsLength; i++) {
12822            var pair = pairs[i];
12823            
12824            if (!pair.isActive || pair.isSensor)
12825                continue;
12826            
12827            var collision = pair.collision,
12828                bodyA = collision.parentA,
12829                bodyB = collision.parentB,
12830                normalX = collision.normal.x,
12831                normalY = collision.normal.y,
12832                tangentX = collision.tangent.x,
12833                tangentY = collision.tangent.y,
12834                inverseMassTotal = pair.inverseMass,
12835                friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier,
12836                contacts = pair.contacts,
12837                contactCount = pair.contactCount,
12838                contactShare = 1 / contactCount;
12839
12840            // get body velocities
12841            var bodyAVelocityX = bodyA.position.x - bodyA.positionPrev.x,
12842                bodyAVelocityY = bodyA.position.y - bodyA.positionPrev.y,
12843                bodyAAngularVelocity = bodyA.angle - bodyA.anglePrev,
12844                bodyBVelocityX = bodyB.position.x - bodyB.positionPrev.x,
12845                bodyBVelocityY = bodyB.position.y - bodyB.positionPrev.y,
12846                bodyBAngularVelocity = bodyB.angle - bodyB.anglePrev;
12847
12848            // resolve each contact
12849            for (j = 0; j < contactCount; j++) {
12850                var contact = contacts[j],
12851                    contactVertex = contact.vertex;
12852
12853                var offsetAX = contactVertex.x - bodyA.position.x,
12854                    offsetAY = contactVertex.y - bodyA.position.y,
12855                    offsetBX = contactVertex.x - bodyB.position.x,
12856                    offsetBY = contactVertex.y - bodyB.position.y;
12857 
12858                var velocityPointAX = bodyAVelocityX - offsetAY * bodyAAngularVelocity,
12859                    velocityPointAY = bodyAVelocityY + offsetAX * bodyAAngularVelocity,
12860                    velocityPointBX = bodyBVelocityX - offsetBY * bodyBAngularVelocity,
12861                    velocityPointBY = bodyBVelocityY + offsetBX * bodyBAngularVelocity;
12862
12863                var relativeVelocityX = velocityPointAX - velocityPointBX,
12864                    relativeVelocityY = velocityPointAY - velocityPointBY;
12865
12866                var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY,
12867                    tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY;
12868
12869                // coulomb friction
12870                var normalOverlap = pair.separation + normalVelocity;
12871                var normalForce = Math.min(normalOverlap, 1);
12872                normalForce = normalOverlap < 0 ? 0 : normalForce;
12873
12874                var frictionLimit = normalForce * friction;
12875
12876                if (tangentVelocity < -frictionLimit || tangentVelocity > frictionLimit) {
12877                    maxFriction = (tangentVelocity > 0 ? tangentVelocity : -tangentVelocity);
12878                    tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScaleCubed;
12879                    
12880                    if (tangentImpulse < -maxFriction) {
12881                        tangentImpulse = -maxFriction;
12882                    } else if (tangentImpulse > maxFriction) {
12883                        tangentImpulse = maxFriction;
12884                    }
12885                } else {
12886                    tangentImpulse = tangentVelocity;
12887                    maxFriction = frictionMaxStatic;
12888                }
12889
12890                // account for mass, inertia and contact offset
12891                var oAcN = offsetAX * normalY - offsetAY * normalX,
12892                    oBcN = offsetBX * normalY - offsetBY * normalX,
12893                    share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);
12894
12895                // raw impulses
12896                var normalImpulse = (1 + pair.restitution) * normalVelocity * share;
12897                tangentImpulse *= share;
12898
12899                // handle high velocity and resting collisions separately
12900                if (normalVelocity < restingThresh) {
12901                    // high normal velocity so clear cached contact normal impulse
12902                    contact.normalImpulse = 0;
12903                } else {
12904                    // solve resting collision constraints using Erin Catto's method (GDC08)
12905                    // impulse constraint tends to 0
12906                    var contactNormalImpulse = contact.normalImpulse;
12907                    contact.normalImpulse += normalImpulse;
12908                    if (contact.normalImpulse > 0) contact.normalImpulse = 0;
12909                    normalImpulse = contact.normalImpulse - contactNormalImpulse;
12910                }
12911
12912                // handle high velocity and resting collisions separately
12913                if (tangentVelocity < -restingThreshTangent || tangentVelocity > restingThreshTangent) {
12914                    // high tangent velocity so clear cached contact tangent impulse
12915                    contact.tangentImpulse = 0;
12916                } else {
12917                    // solve resting collision constraints using Erin Catto's method (GDC08)
12918                    // tangent impulse tends to -tangentSpeed or +tangentSpeed
12919                    var contactTangentImpulse = contact.tangentImpulse;
12920                    contact.tangentImpulse += tangentImpulse;
12921                    if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction;
12922                    if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction;
12923                    tangentImpulse = contact.tangentImpulse - contactTangentImpulse;
12924                }
12925
12926                // total impulse from contact
12927                var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,
12928                    impulseY = normalY * normalImpulse + tangentY * tangentImpulse;
12929                
12930                // apply impulse from contact
12931                if (!(bodyA.isStatic || bodyA.isSleeping)) {
12932                    bodyA.positionPrev.x += impulseX * bodyA.inverseMass;
12933                    bodyA.positionPrev.y += impulseY * bodyA.inverseMass;
12934                    bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;
12935                }
12936
12937                if (!(bodyB.isStatic || bodyB.isSleeping)) {
12938                    bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;
12939                    bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;
12940                    bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia;
12941                }
12942            }
12943        }
12944    };
12945
12946})();
12947
12948
12949/***/ }),
12950/* 19 */
12951/***/ (function(module, exports, __webpack_require__) {
12952
12953/**
12954* The `Matter.Pairs` module contains methods for creating and manipulating collision pair sets.
12955*
12956* @class Pairs
12957*/
12958
12959var Pairs = {};
12960
12961module.exports = Pairs;
12962
12963var Pair = __webpack_require__(9);
12964var Common = __webpack_require__(0);
12965
12966(function() {
12967
12968    /**
12969     * Creates a new pairs structure.
12970     * @method create
12971     * @param {object} options
12972     * @return {pairs} A new pairs structure
12973     */
12974    Pairs.create = function(options) {
12975        return Common.extend({ 
12976            table: {},
12977            list: [],
12978            collisionStart: [],
12979            collisionActive: [],
12980            collisionEnd: []
12981        }, options);
12982    };
12983
12984    /**
12985     * Updates pairs given a list of collisions.
12986     * @method update
12987     * @param {object} pairs
12988     * @param {collision[]} collisions
12989     * @param {number} timestamp
12990     */
12991    Pairs.update = function(pairs, collisions, timestamp) {
12992        var pairUpdate = Pair.update,
12993            pairCreate = Pair.create,
12994            pairSetActive = Pair.setActive,
12995            pairsTable = pairs.table,
12996            pairsList = pairs.list,
12997            pairsListLength = pairsList.length,
12998            pairsListIndex = pairsListLength,
12999            collisionStart = pairs.collisionStart,
13000            collisionEnd = pairs.collisionEnd,
13001            collisionActive = pairs.collisionActive,
13002            collisionsLength = collisions.length,
13003            collisionStartIndex = 0,
13004            collisionEndIndex = 0,
13005            collisionActiveIndex = 0,
13006            collision,
13007            pair,
13008            i;
13009
13010        for (i = 0; i < collisionsLength; i++) {
13011            collision = collisions[i];
13012            pair = collision.pair;
13013
13014            if (pair) {
13015                // pair already exists (but may or may not be active)
13016                if (pair.isActive) {
13017                    // pair exists and is active
13018                    collisionActive[collisionActiveIndex++] = pair;
13019                }
13020
13021                // update the pair
13022                pairUpdate(pair, collision, timestamp);
13023            } else {
13024                // pair did not exist, create a new pair
13025                pair = pairCreate(collision, timestamp);
13026                pairsTable[pair.id] = pair;
13027
13028                // add the new pair
13029                collisionStart[collisionStartIndex++] = pair;
13030                pairsList[pairsListIndex++] = pair;
13031            }
13032        }
13033
13034        // find pairs that are no longer active
13035        pairsListIndex = 0;
13036        pairsListLength = pairsList.length;
13037
13038        for (i = 0; i < pairsListLength; i++) {
13039            pair = pairsList[i];
13040            
13041            // pair is active if updated this timestep
13042            if (pair.timeUpdated >= timestamp) {
13043                // keep active pairs
13044                pairsList[pairsListIndex++] = pair;
13045            } else {
13046                pairSetActive(pair, false, timestamp);
13047
13048                // keep inactive pairs if both bodies may be sleeping
13049                if (pair.collision.bodyA.sleepCounter > 0 && pair.collision.bodyB.sleepCounter > 0) {
13050                    pairsList[pairsListIndex++] = pair;
13051                } else {
13052                    // remove inactive pairs if either body awake
13053                    collisionEnd[collisionEndIndex++] = pair;
13054                    delete pairsTable[pair.id];
13055                }
13056            }
13057        }
13058
13059        // update array lengths if changed
13060        if (pairsList.length !== pairsListIndex) {
13061            pairsList.length = pairsListIndex;
13062        }
13063
13064        if (collisionStart.length !== collisionStartIndex) {
13065            collisionStart.length = collisionStartIndex;
13066        }
13067
13068        if (collisionEnd.length !== collisionEndIndex) {
13069            collisionEnd.length = collisionEndIndex;
13070        }
13071
13072        if (collisionActive.length !== collisionActiveIndex) {
13073            collisionActive.length = collisionActiveIndex;
13074        }
13075    };
13076
13077    /**
13078     * Clears the given pairs structure.
13079     * @method clear
13080     * @param {pairs} pairs
13081     * @return {pairs} pairs
13082     */
13083    Pairs.clear = function(pairs) {
13084        pairs.table = {};
13085        pairs.list.length = 0;
13086        pairs.collisionStart.length = 0;
13087        pairs.collisionActive.length = 0;
13088        pairs.collisionEnd.length = 0;
13089        return pairs;
13090    };
13091
13092})();
13093
13094
13095/***/ }),
13096/* 20 */
13097/***/ (function(module, exports, __webpack_require__) {
13098
13099var Matter = module.exports = __webpack_require__(21);
vendor: 2,660 bytes, lines 13099-13189
13099
13100
13101Matter.Axes = __webpack_require__(11);
13102Matter.Bodies = __webpack_require__(12);
13103Matter.Body = __webpack_require__(4);
13104Matter.Bounds = __webpack_require__(1);
13105Matter.Collision = __webpack_require__(8);
13106Matter.Common = __webpack_require__(0);
13107Matter.Composite = __webpack_require__(6);
13108Matter.Composites = __webpack_require__(22);
13109Matter.Constraint = __webpack_require__(10);
13110Matter.Contact = __webpack_require__(16);
13111Matter.Detector = __webpack_require__(13);
13112Matter.Engine = __webpack_require__(17);
13113Matter.Events = __webpack_require__(5);
13114Matter.Grid = __webpack_require__(23);
13115Matter.Mouse = __webpack_require__(14);
13116Matter.MouseConstraint = __webpack_require__(24);
13117Matter.Pair = __webpack_require__(9);
13118Matter.Pairs = __webpack_require__(19);
13119Matter.Plugin = __webpack_require__(15);
13120Matter.Query = __webpack_require__(25);
13121Matter.Render = __webpack_require__(26);
13122Matter.Resolver = __webpack_require__(18);
13123Matter.Runner = __webpack_require__(27);
13124Matter.SAT = __webpack_require__(28);
13125Matter.Sleeping = __webpack_require__(7);
13126Matter.Svg = __webpack_require__(29);
13127Matter.Vector = __webpack_require__(2);
13128Matter.Vertices = __webpack_require__(3);
13129Matter.World = __webpack_require__(30);
13130
13131// temporary back compatibility
13132Matter.Engine.run = Matter.Runner.run;
13133Matter.Common.deprecated(Matter.Engine, 'run', 'Engine.run ➤ use Matter.Runner.run(engine) instead');
13134
13135
13136/***/ }),
13137/* 21 */
13138/***/ (function(module, exports, __webpack_require__) {
13139
13140/**
13141* The `Matter` module is the top level namespace. It also includes a function for installing plugins on top of the library.
13142*
13143* @class Matter
13144*/
13145
13146var Matter = {};
13147
13148module.exports = Matter;
13149
13150var Plugin = __webpack_require__(15);
13151var Common = __webpack_require__(0);
13152
13153(function() {
13154
13155    /**
13156     * The library name.
13157     * @property name
13158     * @readOnly
13159     * @type {String}
13160     */
13161    Matter.name = 'matter-js';
13162
13163    /**
13164     * The library version.
13165     * @property version
13166     * @readOnly
13167     * @type {String}
13168     */
13169    Matter.version =  true ? "0.20.0" : undefined;
13170
13171    /**
13172     * A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`.
13173     * Alternatively you may set `Matter.uses` manually and install them by calling `Plugin.use(Matter)`.
13174     * @property uses
13175     * @type {Array}
13176     */
13177    Matter.uses = [];
13178
13179    /**
13180     * The plugins that have been installed through `Matter.Plugin.install`. Read only.
13181     * @property used
13182     * @readOnly
13183     * @type {Array}
13184     */
13185    Matter.used = [];
13186
13187    /**
13188     * Installs the given plugins on the `Matter` namespace.
13189     * This is a short-hand for `Plugin.use`, see it for more information.
13190     * Call this function once at the start of your code, with all of the plugins you wish to install as arguments.
13191     * Avoid calling this function multiple times unless you intend to manually control installation order.
13192     * @method use
13193     * @param ...plugin {Function} The plugin(s) to install on `base` (multi-argument).
13194     */
13195    Matter.use = function() {
13196        Plugin.use(Matter, Array.prototype.slice.call(arguments));
13197    };
13198
13199    /**
13200     * Chains a function to excute before the original function on the given `path` relative to `Matter`.
13201     * See also docs for `Common.chain`.
13202     * @method before
13203     * @param {string} path The path relative to `Matter`
13204     * @param {function} func The function to chain before the original
13205     * @return {function} The chained function that replaced the original
13206     */
13207    Matter.before = function(path, func) {
13208        path = path.replace(/^Matter./, '');
13209        return Common.chainPathBefore(Matter, path, func);
13210    };
13211
13212    /**
13213     * Chains a function to excute after the original function on the given `path` relative to `Matter`.
13214     * See also docs for `Common.chain`.
13215     * @method after
13216     * @param {string} path The path relative to `Matter`
13217     * @param {function} func The function to chain after the original
13218     * @return {function} The chained function that replaced the original
13219     */
13220    Matter.after = function(path, func) {
13221        path = path.replace(/^Matter./, '');
13222        return Common.chainPathAfter(Matter, path, func);
13223    };
13224
13225})();
vendor: 122,435 bytes, lines 13225-17001
13225
13226
13227
13228/***/ }),
13229/* 22 */
13230/***/ (function(module, exports, __webpack_require__) {
13231
13232/**
13233* The `Matter.Composites` module contains factory methods for creating composite bodies
13234* with commonly used configurations (such as stacks and chains).
13235*
13236* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
13237*
13238* @class Composites
13239*/
13240
13241var Composites = {};
13242
13243module.exports = Composites;
13244
13245var Composite = __webpack_require__(6);
13246var Constraint = __webpack_require__(10);
13247var Common = __webpack_require__(0);
13248var Body = __webpack_require__(4);
13249var Bodies = __webpack_require__(12);
13250var deprecated = Common.deprecated;
13251
13252(function() {
13253
13254    /**
13255     * Create a new composite containing bodies created in the callback in a grid arrangement.
13256     * This function uses the body's bounds to prevent overlaps.
13257     * @method stack
13258     * @param {number} x Starting position in X.
13259     * @param {number} y Starting position in Y.
13260     * @param {number} columns
13261     * @param {number} rows
13262     * @param {number} columnGap
13263     * @param {number} rowGap
13264     * @param {function} callback
13265     * @return {composite} A new composite containing objects created in the callback
13266     */
13267    Composites.stack = function(x, y, columns, rows, columnGap, rowGap, callback) {
13268        var stack = Composite.create({ label: 'Stack' }),
13269            currentX = x,
13270            currentY = y,
13271            lastBody,
13272            i = 0;
13273
13274        for (var row = 0; row < rows; row++) {
13275            var maxHeight = 0;
13276            
13277            for (var column = 0; column < columns; column++) {
13278                var body = callback(currentX, currentY, column, row, lastBody, i);
13279                    
13280                if (body) {
13281                    var bodyHeight = body.bounds.max.y - body.bounds.min.y,
13282                        bodyWidth = body.bounds.max.x - body.bounds.min.x; 
13283
13284                    if (bodyHeight > maxHeight)
13285                        maxHeight = bodyHeight;
13286                    
13287                    Body.translate(body, { x: bodyWidth * 0.5, y: bodyHeight * 0.5 });
13288
13289                    currentX = body.bounds.max.x + columnGap;
13290
13291                    Composite.addBody(stack, body);
13292                    
13293                    lastBody = body;
13294                    i += 1;
13295                } else {
13296                    currentX += columnGap;
13297                }
13298            }
13299            
13300            currentY += maxHeight + rowGap;
13301            currentX = x;
13302        }
13303
13304        return stack;
13305    };
13306    
13307    /**
13308     * Chains all bodies in the given composite together using constraints.
13309     * @method chain
13310     * @param {composite} composite
13311     * @param {number} xOffsetA
13312     * @param {number} yOffsetA
13313     * @param {number} xOffsetB
13314     * @param {number} yOffsetB
13315     * @param {object} options
13316     * @return {composite} A new composite containing objects chained together with constraints
13317     */
13318    Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options) {
13319        var bodies = composite.bodies;
13320        
13321        for (var i = 1; i < bodies.length; i++) {
13322            var bodyA = bodies[i - 1],
13323                bodyB = bodies[i],
13324                bodyAHeight = bodyA.bounds.max.y - bodyA.bounds.min.y,
13325                bodyAWidth = bodyA.bounds.max.x - bodyA.bounds.min.x, 
13326                bodyBHeight = bodyB.bounds.max.y - bodyB.bounds.min.y,
13327                bodyBWidth = bodyB.bounds.max.x - bodyB.bounds.min.x;
13328        
13329            var defaults = {
13330                bodyA: bodyA,
13331                pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA },
13332                bodyB: bodyB,
13333                pointB: { x: bodyBWidth * xOffsetB, y: bodyBHeight * yOffsetB }
13334            };
13335            
13336            var constraint = Common.extend(defaults, options);
13337        
13338            Composite.addConstraint(composite, Constraint.create(constraint));
13339        }
13340
13341        composite.label += ' Chain';
13342        
13343        return composite;
13344    };
13345
13346    /**
13347     * Connects bodies in the composite with constraints in a grid pattern, with optional cross braces.
13348     * @method mesh
13349     * @param {composite} composite
13350     * @param {number} columns
13351     * @param {number} rows
13352     * @param {boolean} crossBrace
13353     * @param {object} options
13354     * @return {composite} The composite containing objects meshed together with constraints
13355     */
13356    Composites.mesh = function(composite, columns, rows, crossBrace, options) {
13357        var bodies = composite.bodies,
13358            row,
13359            col,
13360            bodyA,
13361            bodyB,
13362            bodyC;
13363        
13364        for (row = 0; row < rows; row++) {
13365            for (col = 1; col < columns; col++) {
13366                bodyA = bodies[(col - 1) + (row * columns)];
13367                bodyB = bodies[col + (row * columns)];
13368                Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options)));
13369            }
13370
13371            if (row > 0) {
13372                for (col = 0; col < columns; col++) {
13373                    bodyA = bodies[col + ((row - 1) * columns)];
13374                    bodyB = bodies[col + (row * columns)];
13375                    Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options)));
13376
13377                    if (crossBrace && col > 0) {
13378                        bodyC = bodies[(col - 1) + ((row - 1) * columns)];
13379                        Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options)));
13380                    }
13381
13382                    if (crossBrace && col < columns - 1) {
13383                        bodyC = bodies[(col + 1) + ((row - 1) * columns)];
13384                        Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options)));
13385                    }
13386                }
13387            }
13388        }
13389
13390        composite.label += ' Mesh';
13391        
13392        return composite;
13393    };
13394    
13395    /**
13396     * Create a new composite containing bodies created in the callback in a pyramid arrangement.
13397     * This function uses the body's bounds to prevent overlaps.
13398     * @method pyramid
13399     * @param {number} x Starting position in X.
13400     * @param {number} y Starting position in Y.
13401     * @param {number} columns
13402     * @param {number} rows
13403     * @param {number} columnGap
13404     * @param {number} rowGap
13405     * @param {function} callback
13406     * @return {composite} A new composite containing objects created in the callback
13407     */
13408    Composites.pyramid = function(x, y, columns, rows, columnGap, rowGap, callback) {
13409        return Composites.stack(x, y, columns, rows, columnGap, rowGap, function(stackX, stackY, column, row, lastBody, i) {
13410            var actualRows = Math.min(rows, Math.ceil(columns / 2)),
13411                lastBodyWidth = lastBody ? lastBody.bounds.max.x - lastBody.bounds.min.x : 0;
13412            
13413            if (row > actualRows)
13414                return;
13415            
13416            // reverse row order
13417            row = actualRows - row;
13418            
13419            var start = row,
13420                end = columns - 1 - row;
13421
13422            if (column < start || column > end)
13423                return;
13424            
13425            // retroactively fix the first body's position, since width was unknown
13426            if (i === 1) {
13427                Body.translate(lastBody, { x: (column + (columns % 2 === 1 ? 1 : -1)) * lastBodyWidth, y: 0 });
13428            }
13429
13430            var xOffset = lastBody ? column * lastBodyWidth : 0;
13431            
13432            return callback(x + xOffset + column * columnGap, stackY, column, row, lastBody, i);
13433        });
13434    };
13435
13436    /**
13437     * This has now moved to the [newtonsCradle example](https://github.com/liabru/matter-js/blob/master/examples/newtonsCradle.js), follow that instead as this function is deprecated here.
13438     * @deprecated moved to newtonsCradle example
13439     * @method newtonsCradle
13440     * @param {number} x Starting position in X.
13441     * @param {number} y Starting position in Y.
13442     * @param {number} number
13443     * @param {number} size
13444     * @param {number} length
13445     * @return {composite} A new composite newtonsCradle body
13446     */
13447    Composites.newtonsCradle = function(x, y, number, size, length) {
13448        var newtonsCradle = Composite.create({ label: 'Newtons Cradle' });
13449
13450        for (var i = 0; i < number; i++) {
13451            var separation = 1.9,
13452                circle = Bodies.circle(x + i * (size * separation), y + length, size, 
13453                    { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }),
13454                constraint = Constraint.create({ pointA: { x: x + i * (size * separation), y: y }, bodyB: circle });
13455
13456            Composite.addBody(newtonsCradle, circle);
13457            Composite.addConstraint(newtonsCradle, constraint);
13458        }
13459
13460        return newtonsCradle;
13461    };
13462
13463    deprecated(Composites, 'newtonsCradle', 'Composites.newtonsCradle ➤ moved to newtonsCradle example');
13464    
13465    /**
13466     * This has now moved to the [car example](https://github.com/liabru/matter-js/blob/master/examples/car.js), follow that instead as this function is deprecated here.
13467     * @deprecated moved to car example
13468     * @method car
13469     * @param {number} x Starting position in X.
13470     * @param {number} y Starting position in Y.
13471     * @param {number} width
13472     * @param {number} height
13473     * @param {number} wheelSize
13474     * @return {composite} A new composite car body
13475     */
13476    Composites.car = function(x, y, width, height, wheelSize) {
13477        var group = Body.nextGroup(true),
13478            wheelBase = 20,
13479            wheelAOffset = -width * 0.5 + wheelBase,
13480            wheelBOffset = width * 0.5 - wheelBase,
13481            wheelYOffset = 0;
13482    
13483        var car = Composite.create({ label: 'Car' }),
13484            body = Bodies.rectangle(x, y, width, height, { 
13485                collisionFilter: {
13486                    group: group
13487                },
13488                chamfer: {
13489                    radius: height * 0.5
13490                },
13491                density: 0.0002
13492            });
13493    
13494        var wheelA = Bodies.circle(x + wheelAOffset, y + wheelYOffset, wheelSize, { 
13495            collisionFilter: {
13496                group: group
13497            },
13498            friction: 0.8
13499        });
13500                    
13501        var wheelB = Bodies.circle(x + wheelBOffset, y + wheelYOffset, wheelSize, { 
13502            collisionFilter: {
13503                group: group
13504            },
13505            friction: 0.8
13506        });
13507                    
13508        var axelA = Constraint.create({
13509            bodyB: body,
13510            pointB: { x: wheelAOffset, y: wheelYOffset },
13511            bodyA: wheelA,
13512            stiffness: 1,
13513            length: 0
13514        });
13515                        
13516        var axelB = Constraint.create({
13517            bodyB: body,
13518            pointB: { x: wheelBOffset, y: wheelYOffset },
13519            bodyA: wheelB,
13520            stiffness: 1,
13521            length: 0
13522        });
13523        
13524        Composite.addBody(car, body);
13525        Composite.addBody(car, wheelA);
13526        Composite.addBody(car, wheelB);
13527        Composite.addConstraint(car, axelA);
13528        Composite.addConstraint(car, axelB);
13529
13530        return car;
13531    };
13532
13533    deprecated(Composites, 'car', 'Composites.car ➤ moved to car example');
13534
13535    /**
13536     * This has now moved to the [softBody example](https://github.com/liabru/matter-js/blob/master/examples/softBody.js)
13537     * and the [cloth example](https://github.com/liabru/matter-js/blob/master/examples/cloth.js), follow those instead as this function is deprecated here.
13538     * @deprecated moved to softBody and cloth examples
13539     * @method softBody
13540     * @param {number} x Starting position in X.
13541     * @param {number} y Starting position in Y.
13542     * @param {number} columns
13543     * @param {number} rows
13544     * @param {number} columnGap
13545     * @param {number} rowGap
13546     * @param {boolean} crossBrace
13547     * @param {number} particleRadius
13548     * @param {} particleOptions
13549     * @param {} constraintOptions
13550     * @return {composite} A new composite softBody
13551     */
13552    Composites.softBody = function(x, y, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) {
13553        particleOptions = Common.extend({ inertia: Infinity }, particleOptions);
13554        constraintOptions = Common.extend({ stiffness: 0.2, render: { type: 'line', anchors: false } }, constraintOptions);
13555
13556        var softBody = Composites.stack(x, y, columns, rows, columnGap, rowGap, function(stackX, stackY) {
13557            return Bodies.circle(stackX, stackY, particleRadius, particleOptions);
13558        });
13559
13560        Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions);
13561
13562        softBody.label = 'Soft Body';
13563
13564        return softBody;
13565    };
13566
13567    deprecated(Composites, 'softBody', 'Composites.softBody ➤ moved to softBody and cloth examples');
13568})();
13569
13570
13571/***/ }),
13572/* 23 */
13573/***/ (function(module, exports, __webpack_require__) {
13574
13575/**
13576* This module has now been replaced by `Matter.Detector`.
13577*
13578* All usage should be migrated to `Matter.Detector` or another alternative.
13579* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
13580*
13581* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures.
13582*
13583* @class Grid
13584* @deprecated
13585*/
13586
13587var Grid = {};
13588
13589module.exports = Grid;
13590
13591var Pair = __webpack_require__(9);
13592var Common = __webpack_require__(0);
13593var deprecated = Common.deprecated;
13594
13595(function() {
13596
13597    /**
13598     * Creates a new grid.
13599     * @deprecated replaced by Matter.Detector
13600     * @method create
13601     * @param {} options
13602     * @return {grid} A new grid
13603     */
13604    Grid.create = function(options) {
13605        var defaults = {
13606            buckets: {},
13607            pairs: {},
13608            pairsList: [],
13609            bucketWidth: 48,
13610            bucketHeight: 48
13611        };
13612
13613        return Common.extend(defaults, options);
13614    };
13615
13616    /**
13617     * The width of a single grid bucket.
13618     *
13619     * @property bucketWidth
13620     * @type number
13621     * @default 48
13622     */
13623
13624    /**
13625     * The height of a single grid bucket.
13626     *
13627     * @property bucketHeight
13628     * @type number
13629     * @default 48
13630     */
13631
13632    /**
13633     * Updates the grid.
13634     * @deprecated replaced by Matter.Detector
13635     * @method update
13636     * @param {grid} grid
13637     * @param {body[]} bodies
13638     * @param {engine} engine
13639     * @param {boolean} forceUpdate
13640     */
13641    Grid.update = function(grid, bodies, engine, forceUpdate) {
13642        var i, col, row,
13643            world = engine.world,
13644            buckets = grid.buckets,
13645            bucket,
13646            bucketId,
13647            gridChanged = false;
13648
13649        for (i = 0; i < bodies.length; i++) {
13650            var body = bodies[i];
13651
13652            if (body.isSleeping && !forceUpdate)
13653                continue;
13654
13655            // temporary back compatibility bounds check
13656            if (world.bounds && (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x
13657                || body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y))
13658                continue;
13659
13660            var newRegion = Grid._getRegion(grid, body);
13661
13662            // if the body has changed grid region
13663            if (!body.region || newRegion.id !== body.region.id || forceUpdate) {
13664
13665                if (!body.region || forceUpdate)
13666                    body.region = newRegion;
13667
13668                var union = Grid._regionUnion(newRegion, body.region);
13669
13670                // update grid buckets affected by region change
13671                // iterate over the union of both regions
13672                for (col = union.startCol; col <= union.endCol; col++) {
13673                    for (row = union.startRow; row <= union.endRow; row++) {
13674                        bucketId = Grid._getBucketId(col, row);
13675                        bucket = buckets[bucketId];
13676
13677                        var isInsideNewRegion = (col >= newRegion.startCol && col <= newRegion.endCol
13678                                                && row >= newRegion.startRow && row <= newRegion.endRow);
13679
13680                        var isInsideOldRegion = (col >= body.region.startCol && col <= body.region.endCol
13681                                                && row >= body.region.startRow && row <= body.region.endRow);
13682
13683                        // remove from old region buckets
13684                        if (!isInsideNewRegion && isInsideOldRegion) {
13685                            if (isInsideOldRegion) {
13686                                if (bucket)
13687                                    Grid._bucketRemoveBody(grid, bucket, body);
13688                            }
13689                        }
13690
13691                        // add to new region buckets
13692                        if (body.region === newRegion || (isInsideNewRegion && !isInsideOldRegion) || forceUpdate) {
13693                            if (!bucket)
13694                                bucket = Grid._createBucket(buckets, bucketId);
13695                            Grid._bucketAddBody(grid, bucket, body);
13696                        }
13697                    }
13698                }
13699
13700                // set the new region
13701                body.region = newRegion;
13702
13703                // flag changes so we can update pairs
13704                gridChanged = true;
13705            }
13706        }
13707
13708        // update pairs list only if pairs changed (i.e. a body changed region)
13709        if (gridChanged)
13710            grid.pairsList = Grid._createActivePairsList(grid);
13711    };
13712
13713    deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector');
13714
13715    /**
13716     * Clears the grid.
13717     * @deprecated replaced by Matter.Detector
13718     * @method clear
13719     * @param {grid} grid
13720     */
13721    Grid.clear = function(grid) {
13722        grid.buckets = {};
13723        grid.pairs = {};
13724        grid.pairsList = [];
13725    };
13726
13727    deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector');
13728
13729    /**
13730     * Finds the union of two regions.
13731     * @method _regionUnion
13732     * @deprecated replaced by Matter.Detector
13733     * @private
13734     * @param {} regionA
13735     * @param {} regionB
13736     * @return {} region
13737     */
13738    Grid._regionUnion = function(regionA, regionB) {
13739        var startCol = Math.min(regionA.startCol, regionB.startCol),
13740            endCol = Math.max(regionA.endCol, regionB.endCol),
13741            startRow = Math.min(regionA.startRow, regionB.startRow),
13742            endRow = Math.max(regionA.endRow, regionB.endRow);
13743
13744        return Grid._createRegion(startCol, endCol, startRow, endRow);
13745    };
13746
13747    /**
13748     * Gets the region a given body falls in for a given grid.
13749     * @method _getRegion
13750     * @deprecated replaced by Matter.Detector
13751     * @private
13752     * @param {} grid
13753     * @param {} body
13754     * @return {} region
13755     */
13756    Grid._getRegion = function(grid, body) {
13757        var bounds = body.bounds,
13758            startCol = Math.floor(bounds.min.x / grid.bucketWidth),
13759            endCol = Math.floor(bounds.max.x / grid.bucketWidth),
13760            startRow = Math.floor(bounds.min.y / grid.bucketHeight),
13761            endRow = Math.floor(bounds.max.y / grid.bucketHeight);
13762
13763        return Grid._createRegion(startCol, endCol, startRow, endRow);
13764    };
13765
13766    /**
13767     * Creates a region.
13768     * @method _createRegion
13769     * @deprecated replaced by Matter.Detector
13770     * @private
13771     * @param {} startCol
13772     * @param {} endCol
13773     * @param {} startRow
13774     * @param {} endRow
13775     * @return {} region
13776     */
13777    Grid._createRegion = function(startCol, endCol, startRow, endRow) {
13778        return { 
13779            id: startCol + ',' + endCol + ',' + startRow + ',' + endRow,
13780            startCol: startCol, 
13781            endCol: endCol, 
13782            startRow: startRow, 
13783            endRow: endRow 
13784        };
13785    };
13786
13787    /**
13788     * Gets the bucket id at the given position.
13789     * @method _getBucketId
13790     * @deprecated replaced by Matter.Detector
13791     * @private
13792     * @param {} column
13793     * @param {} row
13794     * @return {string} bucket id
13795     */
13796    Grid._getBucketId = function(column, row) {
13797        return 'C' + column + 'R' + row;
13798    };
13799
13800    /**
13801     * Creates a bucket.
13802     * @method _createBucket
13803     * @deprecated replaced by Matter.Detector
13804     * @private
13805     * @param {} buckets
13806     * @param {} bucketId
13807     * @return {} bucket
13808     */
13809    Grid._createBucket = function(buckets, bucketId) {
13810        var bucket = buckets[bucketId] = [];
13811        return bucket;
13812    };
13813
13814    /**
13815     * Adds a body to a bucket.
13816     * @method _bucketAddBody
13817     * @deprecated replaced by Matter.Detector
13818     * @private
13819     * @param {} grid
13820     * @param {} bucket
13821     * @param {} body
13822     */
13823    Grid._bucketAddBody = function(grid, bucket, body) {
13824        var gridPairs = grid.pairs,
13825            pairId = Pair.id,
13826            bucketLength = bucket.length,
13827            i;
13828
13829        // add new pairs
13830        for (i = 0; i < bucketLength; i++) {
13831            var bodyB = bucket[i];
13832
13833            if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic))
13834                continue;
13835
13836            // keep track of the number of buckets the pair exists in
13837            // important for Grid.update to work
13838            var id = pairId(body, bodyB),
13839                pair = gridPairs[id];
13840
13841            if (pair) {
13842                pair[2] += 1;
13843            } else {
13844                gridPairs[id] = [body, bodyB, 1];
13845            }
13846        }
13847
13848        // add to bodies (after pairs, otherwise pairs with self)
13849        bucket.push(body);
13850    };
13851
13852    /**
13853     * Removes a body from a bucket.
13854     * @method _bucketRemoveBody
13855     * @deprecated replaced by Matter.Detector
13856     * @private
13857     * @param {} grid
13858     * @param {} bucket
13859     * @param {} body
13860     */
13861    Grid._bucketRemoveBody = function(grid, bucket, body) {
13862        var gridPairs = grid.pairs,
13863            pairId = Pair.id,
13864            i;
13865
13866        // remove from bucket
13867        bucket.splice(Common.indexOf(bucket, body), 1);
13868
13869        var bucketLength = bucket.length;
13870
13871        // update pair counts
13872        for (i = 0; i < bucketLength; i++) {
13873            // keep track of the number of buckets the pair exists in
13874            // important for _createActivePairsList to work
13875            var pair = gridPairs[pairId(body, bucket[i])];
13876
13877            if (pair)
13878                pair[2] -= 1;
13879        }
13880    };
13881
13882    /**
13883     * Generates a list of the active pairs in the grid.
13884     * @method _createActivePairsList
13885     * @deprecated replaced by Matter.Detector
13886     * @private
13887     * @param {} grid
13888     * @return [] pairs
13889     */
13890    Grid._createActivePairsList = function(grid) {
13891        var pair,
13892            gridPairs = grid.pairs,
13893            pairKeys = Common.keys(gridPairs),
13894            pairKeysLength = pairKeys.length,
13895            pairs = [],
13896            k;
13897
13898        // iterate over grid.pairs
13899        for (k = 0; k < pairKeysLength; k++) {
13900            pair = gridPairs[pairKeys[k]];
13901
13902            // if pair exists in at least one bucket
13903            // it is a pair that needs further collision testing so push it
13904            if (pair[2] > 0) {
13905                pairs.push(pair);
13906            } else {
13907                delete gridPairs[pairKeys[k]];
13908            }
13909        }
13910
13911        return pairs;
13912    };
13913    
13914})();
13915
13916
13917/***/ }),
13918/* 24 */
13919/***/ (function(module, exports, __webpack_require__) {
13920
13921/**
13922* The `Matter.MouseConstraint` module contains methods for creating mouse constraints.
13923* Mouse constraints are used for allowing user interaction, providing the ability to move bodies via the mouse or touch.
13924*
13925* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
13926*
13927* @class MouseConstraint
13928*/
13929
13930var MouseConstraint = {};
13931
13932module.exports = MouseConstraint;
13933
13934var Vertices = __webpack_require__(3);
13935var Sleeping = __webpack_require__(7);
13936var Mouse = __webpack_require__(14);
13937var Events = __webpack_require__(5);
13938var Detector = __webpack_require__(13);
13939var Constraint = __webpack_require__(10);
13940var Composite = __webpack_require__(6);
13941var Common = __webpack_require__(0);
13942var Bounds = __webpack_require__(1);
13943
13944(function() {
13945
13946    /**
13947     * Creates a new mouse constraint.
13948     * All properties have default values, and many are pre-calculated automatically based on other properties.
13949     * See the properties section below for detailed information on what you can pass via the `options` object.
13950     * @method create
13951     * @param {engine} engine
13952     * @param {} options
13953     * @return {MouseConstraint} A new MouseConstraint
13954     */
13955    MouseConstraint.create = function(engine, options) {
13956        var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null);
13957
13958        if (!mouse) {
13959            if (engine && engine.render && engine.render.canvas) {
13960                mouse = Mouse.create(engine.render.canvas);
13961            } else if (options && options.element) {
13962                mouse = Mouse.create(options.element);
13963            } else {
13964                mouse = Mouse.create();
13965                Common.warn('MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected');
13966            }
13967        }
13968
13969        var constraint = Constraint.create({ 
13970            label: 'Mouse Constraint',
13971            pointA: mouse.position,
13972            pointB: { x: 0, y: 0 },
13973            length: 0.01, 
13974            stiffness: 0.1,
13975            angularStiffness: 1,
13976            render: {
13977                strokeStyle: '#90EE90',
13978                lineWidth: 3
13979            }
13980        });
13981
13982        var defaults = {
13983            type: 'mouseConstraint',
13984            mouse: mouse,
13985            element: null,
13986            body: null,
13987            constraint: constraint,
13988            collisionFilter: {
13989                category: 0x0001,
13990                mask: 0xFFFFFFFF,
13991                group: 0
13992            }
13993        };
13994
13995        var mouseConstraint = Common.extend(defaults, options);
13996
13997        Events.on(engine, 'beforeUpdate', function() {
13998            var allBodies = Composite.allBodies(engine.world);
13999            MouseConstraint.update(mouseConstraint, allBodies);
14000            MouseConstraint._triggerEvents(mouseConstraint);
14001        });
14002
14003        return mouseConstraint;
14004    };
14005
14006    /**
14007     * Updates the given mouse constraint.
14008     * @private
14009     * @method update
14010     * @param {MouseConstraint} mouseConstraint
14011     * @param {body[]} bodies
14012     */
14013    MouseConstraint.update = function(mouseConstraint, bodies) {
14014        var mouse = mouseConstraint.mouse,
14015            constraint = mouseConstraint.constraint,
14016            body = mouseConstraint.body;
14017
14018        if (mouse.button === 0) {
14019            if (!constraint.bodyB) {
14020                for (var i = 0; i < bodies.length; i++) {
14021                    body = bodies[i];
14022                    if (Bounds.contains(body.bounds, mouse.position) 
14023                            && Detector.canCollide(body.collisionFilter, mouseConstraint.collisionFilter)) {
14024                        for (var j = body.parts.length > 1 ? 1 : 0; j < body.parts.length; j++) {
14025                            var part = body.parts[j];
14026                            if (Vertices.contains(part.vertices, mouse.position)) {
14027                                constraint.pointA = mouse.position;
14028                                constraint.bodyB = mouseConstraint.body = body;
14029                                constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y };
14030                                constraint.angleB = body.angle;
14031
14032                                Sleeping.set(body, false);
14033                                Events.trigger(mouseConstraint, 'startdrag', { mouse: mouse, body: body });
14034
14035                                break;
14036                            }
14037                        }
14038                    }
14039                }
14040            } else {
14041                Sleeping.set(constraint.bodyB, false);
14042                constraint.pointA = mouse.position;
14043            }
14044        } else {
14045            constraint.bodyB = mouseConstraint.body = null;
14046            constraint.pointB = null;
14047
14048            if (body)
14049                Events.trigger(mouseConstraint, 'enddrag', { mouse: mouse, body: body });
14050        }
14051    };
14052
14053    /**
14054     * Triggers mouse constraint events.
14055     * @method _triggerEvents
14056     * @private
14057     * @param {mouse} mouseConstraint
14058     */
14059    MouseConstraint._triggerEvents = function(mouseConstraint) {
14060        var mouse = mouseConstraint.mouse,
14061            mouseEvents = mouse.sourceEvents;
14062
14063        if (mouseEvents.mousemove)
14064            Events.trigger(mouseConstraint, 'mousemove', { mouse: mouse });
14065
14066        if (mouseEvents.mousedown)
14067            Events.trigger(mouseConstraint, 'mousedown', { mouse: mouse });
14068
14069        if (mouseEvents.mouseup)
14070            Events.trigger(mouseConstraint, 'mouseup', { mouse: mouse });
14071
14072        // reset the mouse state ready for the next step
14073        Mouse.clearSourceEvents(mouse);
14074    };
14075
14076    /*
14077    *
14078    *  Events Documentation
14079    *
14080    */
14081
14082    /**
14083    * Fired when the mouse has moved (or a touch moves) during the last step
14084    *
14085    * @event mousemove
14086    * @param {} event An event object
14087    * @param {mouse} event.mouse The engine's mouse instance
14088    * @param {} event.source The source object of the event
14089    * @param {} event.name The name of the event
14090    */
14091
14092    /**
14093    * Fired when the mouse is down (or a touch has started) during the last step
14094    *
14095    * @event mousedown
14096    * @param {} event An event object
14097    * @param {mouse} event.mouse The engine's mouse instance
14098    * @param {} event.source The source object of the event
14099    * @param {} event.name The name of the event
14100    */
14101
14102    /**
14103    * Fired when the mouse is up (or a touch has ended) during the last step
14104    *
14105    * @event mouseup
14106    * @param {} event An event object
14107    * @param {mouse} event.mouse The engine's mouse instance
14108    * @param {} event.source The source object of the event
14109    * @param {} event.name The name of the event
14110    */
14111
14112    /**
14113    * Fired when the user starts dragging a body
14114    *
14115    * @event startdrag
14116    * @param {} event An event object
14117    * @param {mouse} event.mouse The engine's mouse instance
14118    * @param {body} event.body The body being dragged
14119    * @param {} event.source The source object of the event
14120    * @param {} event.name The name of the event
14121    */
14122
14123    /**
14124    * Fired when the user ends dragging a body
14125    *
14126    * @event enddrag
14127    * @param {} event An event object
14128    * @param {mouse} event.mouse The engine's mouse instance
14129    * @param {body} event.body The body that has stopped being dragged
14130    * @param {} event.source The source object of the event
14131    * @param {} event.name The name of the event
14132    */
14133
14134    /*
14135    *
14136    *  Properties Documentation
14137    *
14138    */
14139
14140    /**
14141     * A `String` denoting the type of object.
14142     *
14143     * @property type
14144     * @type string
14145     * @default "constraint"
14146     * @readOnly
14147     */
14148
14149    /**
14150     * The `Mouse` instance in use. If not supplied in `MouseConstraint.create`, one will be created.
14151     *
14152     * @property mouse
14153     * @type mouse
14154     * @default mouse
14155     */
14156
14157    /**
14158     * The `Body` that is currently being moved by the user, or `null` if no body.
14159     *
14160     * @property body
14161     * @type body
14162     * @default null
14163     */
14164
14165    /**
14166     * The `Constraint` object that is used to move the body during interaction.
14167     *
14168     * @property constraint
14169     * @type constraint
14170     */
14171
14172    /**
14173     * An `Object` that specifies the collision filter properties.
14174     * The collision filter allows the user to define which types of body this mouse constraint can interact with.
14175     * See `body.collisionFilter` for more information.
14176     *
14177     * @property collisionFilter
14178     * @type object
14179     */
14180
14181})();
14182
14183
14184/***/ }),
14185/* 25 */
14186/***/ (function(module, exports, __webpack_require__) {
14187
14188/**
14189* The `Matter.Query` module contains methods for performing collision queries.
14190*
14191* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
14192*
14193* @class Query
14194*/
14195
14196var Query = {};
14197
14198module.exports = Query;
14199
14200var Vector = __webpack_require__(2);
14201var Collision = __webpack_require__(8);
14202var Bounds = __webpack_require__(1);
14203var Bodies = __webpack_require__(12);
14204var Vertices = __webpack_require__(3);
14205
14206(function() {
14207
14208    /**
14209     * Returns a list of collisions between `body` and `bodies`.
14210     * @method collides
14211     * @param {body} body
14212     * @param {body[]} bodies
14213     * @return {collision[]} Collisions
14214     */
14215    Query.collides = function(body, bodies) {
14216        var collisions = [],
14217            bodiesLength = bodies.length,
14218            bounds = body.bounds,
14219            collides = Collision.collides,
14220            overlaps = Bounds.overlaps;
14221
14222        for (var i = 0; i < bodiesLength; i++) {
14223            var bodyA = bodies[i],
14224                partsALength = bodyA.parts.length,
14225                partsAStart = partsALength === 1 ? 0 : 1;
14226            
14227            if (overlaps(bodyA.bounds, bounds)) {
14228                for (var j = partsAStart; j < partsALength; j++) {
14229                    var part = bodyA.parts[j];
14230
14231                    if (overlaps(part.bounds, bounds)) {
14232                        var collision = collides(part, body);
14233
14234                        if (collision) {
14235                            collisions.push(collision);
14236                            break;
14237                        }
14238                    }
14239                }
14240            }
14241        }
14242
14243        return collisions;
14244    };
14245
14246    /**
14247     * Casts a ray segment against a set of bodies and returns all collisions, ray width is optional. Intersection points are not provided.
14248     * @method ray
14249     * @param {body[]} bodies
14250     * @param {vector} startPoint
14251     * @param {vector} endPoint
14252     * @param {number} [rayWidth]
14253     * @return {collision[]} Collisions
14254     */
14255    Query.ray = function(bodies, startPoint, endPoint, rayWidth) {
14256        rayWidth = rayWidth || 1e-100;
14257
14258        var rayAngle = Vector.angle(startPoint, endPoint),
14259            rayLength = Vector.magnitude(Vector.sub(startPoint, endPoint)),
14260            rayX = (endPoint.x + startPoint.x) * 0.5,
14261            rayY = (endPoint.y + startPoint.y) * 0.5,
14262            ray = Bodies.rectangle(rayX, rayY, rayLength, rayWidth, { angle: rayAngle }),
14263            collisions = Query.collides(ray, bodies);
14264
14265        for (var i = 0; i < collisions.length; i += 1) {
14266            var collision = collisions[i];
14267            collision.body = collision.bodyB = collision.bodyA;            
14268        }
14269
14270        return collisions;
14271    };
14272
14273    /**
14274     * Returns all bodies whose bounds are inside (or outside if set) the given set of bounds, from the given set of bodies.
14275     * @method region
14276     * @param {body[]} bodies
14277     * @param {bounds} bounds
14278     * @param {bool} [outside=false]
14279     * @return {body[]} The bodies matching the query
14280     */
14281    Query.region = function(bodies, bounds, outside) {
14282        var result = [];
14283
14284        for (var i = 0; i < bodies.length; i++) {
14285            var body = bodies[i],
14286                overlaps = Bounds.overlaps(body.bounds, bounds);
14287            if ((overlaps && !outside) || (!overlaps && outside))
14288                result.push(body);
14289        }
14290
14291        return result;
14292    };
14293
14294    /**
14295     * Returns all bodies whose vertices contain the given point, from the given set of bodies.
14296     * @method point
14297     * @param {body[]} bodies
14298     * @param {vector} point
14299     * @return {body[]} The bodies matching the query
14300     */
14301    Query.point = function(bodies, point) {
14302        var result = [];
14303
14304        for (var i = 0; i < bodies.length; i++) {
14305            var body = bodies[i];
14306            
14307            if (Bounds.contains(body.bounds, point)) {
14308                for (var j = body.parts.length === 1 ? 0 : 1; j < body.parts.length; j++) {
14309                    var part = body.parts[j];
14310
14311                    if (Bounds.contains(part.bounds, point)
14312                        && Vertices.contains(part.vertices, point)) {
14313                        result.push(body);
14314                        break;
14315                    }
14316                }
14317            }
14318        }
14319
14320        return result;
14321    };
14322
14323})();
14324
14325
14326/***/ }),
14327/* 26 */
14328/***/ (function(module, exports, __webpack_require__) {
14329
14330/**
14331* The `Matter.Render` module is a lightweight, optional utility which provides a simple canvas based renderer for visualising instances of `Matter.Engine`.
14332* It is intended for development and debugging purposes, but may also be suitable for simple games.
14333* It includes a number of drawing options including wireframe, vector with support for sprites and viewports.
14334*
14335* @class Render
14336*/
14337
14338var Render = {};
14339
14340module.exports = Render;
14341
14342var Body = __webpack_require__(4);
14343var Common = __webpack_require__(0);
14344var Composite = __webpack_require__(6);
14345var Bounds = __webpack_require__(1);
14346var Events = __webpack_require__(5);
14347var Vector = __webpack_require__(2);
14348var Mouse = __webpack_require__(14);
14349
14350(function() {
14351
14352    var _requestAnimationFrame,
14353        _cancelAnimationFrame;
14354
14355    if (typeof window !== 'undefined') {
14356        _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame
14357                                      || window.mozRequestAnimationFrame || window.msRequestAnimationFrame
14358                                      || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); };
14359
14360        _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame
14361                                      || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
14362    }
14363
14364    Render._goodFps = 30;
14365    Render._goodDelta = 1000 / 60;
14366
14367    /**
14368     * Creates a new renderer. The options parameter is an object that specifies any properties you wish to override the defaults.
14369     * All properties have default values, and many are pre-calculated automatically based on other properties.
14370     * See the properties section below for detailed information on what you can pass via the `options` object.
14371     * @method create
14372     * @param {object} [options]
14373     * @return {render} A new renderer
14374     */
14375    Render.create = function(options) {
14376        var defaults = {
14377            engine: null,
14378            element: null,
14379            canvas: null,
14380            mouse: null,
14381            frameRequestId: null,
14382            timing: {
14383                historySize: 60,
14384                delta: 0,
14385                deltaHistory: [],
14386                lastTime: 0,
14387                lastTimestamp: 0,
14388                lastElapsed: 0,
14389                timestampElapsed: 0,
14390                timestampElapsedHistory: [],
14391                engineDeltaHistory: [],
14392                engineElapsedHistory: [],
14393                engineUpdatesHistory: [],
14394                elapsedHistory: []
14395            },
14396            options: {
14397                width: 800,
14398                height: 600,
14399                pixelRatio: 1,
14400                background: '#14151f',
14401                wireframeBackground: '#14151f',
14402                wireframeStrokeStyle: '#bbb',
14403                hasBounds: !!options.bounds,
14404                enabled: true,
14405                wireframes: true,
14406                showSleeping: true,
14407                showDebug: false,
14408                showStats: false,
14409                showPerformance: false,
14410                showBounds: false,
14411                showVelocity: false,
14412                showCollisions: false,
14413                showSeparations: false,
14414                showAxes: false,
14415                showPositions: false,
14416                showAngleIndicator: false,
14417                showIds: false,
14418                showVertexNumbers: false,
14419                showConvexHulls: false,
14420                showInternalEdges: false,
14421                showMousePosition: false
14422            }
14423        };
14424
14425        var render = Common.extend(defaults, options);
14426
14427        if (render.canvas) {
14428            render.canvas.width = render.options.width || render.canvas.width;
14429            render.canvas.height = render.options.height || render.canvas.height;
14430        }
14431
14432        render.mouse = options.mouse;
14433        render.engine = options.engine;
14434        render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height);
14435        render.context = render.canvas.getContext('2d');
14436        render.textures = {};
14437
14438        render.bounds = render.bounds || {
14439            min: {
14440                x: 0,
14441                y: 0
14442            },
14443            max: {
14444                x: render.canvas.width,
14445                y: render.canvas.height
14446            }
14447        };
14448
14449        // for temporary back compatibility only
14450        render.controller = Render;
14451        render.options.showBroadphase = false;
14452
14453        if (render.options.pixelRatio !== 1) {
14454            Render.setPixelRatio(render, render.options.pixelRatio);
14455        }
14456
14457        if (Common.isElement(render.element)) {
14458            render.element.appendChild(render.canvas);
14459        }
14460
14461        return render;
14462    };
14463
14464    /**
14465     * Continuously updates the render canvas on the `requestAnimationFrame` event.
14466     * @method run
14467     * @param {render} render
14468     */
14469    Render.run = function(render) {
14470        (function loop(time){
14471            render.frameRequestId = _requestAnimationFrame(loop);
14472            
14473            _updateTiming(render, time);
14474
14475            Render.world(render, time);
14476
14477            render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0);
14478
14479            if (render.options.showStats || render.options.showDebug) {
14480                Render.stats(render, render.context, time);
14481            }
14482
14483            if (render.options.showPerformance || render.options.showDebug) {
14484                Render.performance(render, render.context, time);
14485            }
14486
14487            render.context.setTransform(1, 0, 0, 1, 0, 0);
14488        })();
14489    };
14490
14491    /**
14492     * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop.
14493     * @method stop
14494     * @param {render} render
14495     */
14496    Render.stop = function(render) {
14497        _cancelAnimationFrame(render.frameRequestId);
14498    };
14499
14500    /**
14501     * Sets the pixel ratio of the renderer and updates the canvas.
14502     * To automatically detect the correct ratio, pass the string `'auto'` for `pixelRatio`.
14503     * @method setPixelRatio
14504     * @param {render} render
14505     * @param {number} pixelRatio
14506     */
14507    Render.setPixelRatio = function(render, pixelRatio) {
14508        var options = render.options,
14509            canvas = render.canvas;
14510
14511        if (pixelRatio === 'auto') {
14512            pixelRatio = _getPixelRatio(canvas);
14513        }
14514
14515        options.pixelRatio = pixelRatio;
14516        canvas.setAttribute('data-pixel-ratio', pixelRatio);
14517        canvas.width = options.width * pixelRatio;
14518        canvas.height = options.height * pixelRatio;
14519        canvas.style.width = options.width + 'px';
14520        canvas.style.height = options.height + 'px';
14521    };
14522
14523    /**
14524     * Sets the render `width` and `height`.
14525     * 
14526     * Updates the canvas accounting for `render.options.pixelRatio`.  
14527     * 
14528     * Updates the bottom right render bound `render.bounds.max` relative to the provided `width` and `height`.
14529     * The top left render bound `render.bounds.min` isn't changed.
14530     * 
14531     * Follow this call with `Render.lookAt` if you need to change the render bounds.
14532     * 
14533     * See also `Render.setPixelRatio`.
14534     * @method setSize
14535     * @param {render} render
14536     * @param {number} width The width (in CSS pixels)
14537     * @param {number} height The height (in CSS pixels)
14538     */
14539    Render.setSize = function(render, width, height) {
14540        render.options.width = width;
14541        render.options.height = height;
14542        render.bounds.max.x = render.bounds.min.x + width;
14543        render.bounds.max.y = render.bounds.min.y + height;
14544
14545        if (render.options.pixelRatio !== 1) {
14546            Render.setPixelRatio(render, render.options.pixelRatio);
14547        } else {
14548            render.canvas.width = width;
14549            render.canvas.height = height;
14550        }
14551    };
14552
14553    /**
14554     * Positions and sizes the viewport around the given object bounds.
14555     * Objects must have at least one of the following properties:
14556     * - `object.bounds`
14557     * - `object.position`
14558     * - `object.min` and `object.max`
14559     * - `object.x` and `object.y`
14560     * @method lookAt
14561     * @param {render} render
14562     * @param {object[]} objects
14563     * @param {vector} [padding]
14564     * @param {bool} [center=true]
14565     */
14566    Render.lookAt = function(render, objects, padding, center) {
14567        center = typeof center !== 'undefined' ? center : true;
14568        objects = Common.isArray(objects) ? objects : [objects];
14569        padding = padding || {
14570            x: 0,
14571            y: 0
14572        };
14573
14574        // find bounds of all objects
14575        var bounds = {
14576            min: { x: Infinity, y: Infinity },
14577            max: { x: -Infinity, y: -Infinity }
14578        };
14579
14580        for (var i = 0; i < objects.length; i += 1) {
14581            var object = objects[i],
14582                min = object.bounds ? object.bounds.min : (object.min || object.position || object),
14583                max = object.bounds ? object.bounds.max : (object.max || object.position || object);
14584
14585            if (min && max) {
14586                if (min.x < bounds.min.x)
14587                    bounds.min.x = min.x;
14588
14589                if (max.x > bounds.max.x)
14590                    bounds.max.x = max.x;
14591
14592                if (min.y < bounds.min.y)
14593                    bounds.min.y = min.y;
14594
14595                if (max.y > bounds.max.y)
14596                    bounds.max.y = max.y;
14597            }
14598        }
14599
14600        // find ratios
14601        var width = (bounds.max.x - bounds.min.x) + 2 * padding.x,
14602            height = (bounds.max.y - bounds.min.y) + 2 * padding.y,
14603            viewHeight = render.canvas.height,
14604            viewWidth = render.canvas.width,
14605            outerRatio = viewWidth / viewHeight,
14606            innerRatio = width / height,
14607            scaleX = 1,
14608            scaleY = 1;
14609
14610        // find scale factor
14611        if (innerRatio > outerRatio) {
14612            scaleY = innerRatio / outerRatio;
14613        } else {
14614            scaleX = outerRatio / innerRatio;
14615        }
14616
14617        // enable bounds
14618        render.options.hasBounds = true;
14619
14620        // position and size
14621        render.bounds.min.x = bounds.min.x;
14622        render.bounds.max.x = bounds.min.x + width * scaleX;
14623        render.bounds.min.y = bounds.min.y;
14624        render.bounds.max.y = bounds.min.y + height * scaleY;
14625
14626        // center
14627        if (center) {
14628            render.bounds.min.x += width * 0.5 - (width * scaleX) * 0.5;
14629            render.bounds.max.x += width * 0.5 - (width * scaleX) * 0.5;
14630            render.bounds.min.y += height * 0.5 - (height * scaleY) * 0.5;
14631            render.bounds.max.y += height * 0.5 - (height * scaleY) * 0.5;
14632        }
14633
14634        // padding
14635        render.bounds.min.x -= padding.x;
14636        render.bounds.max.x -= padding.x;
14637        render.bounds.min.y -= padding.y;
14638        render.bounds.max.y -= padding.y;
14639
14640        // update mouse
14641        if (render.mouse) {
14642            Mouse.setScale(render.mouse, {
14643                x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width,
14644                y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height
14645            });
14646
14647            Mouse.setOffset(render.mouse, render.bounds.min);
14648        }
14649    };
14650
14651    /**
14652     * Applies viewport transforms based on `render.bounds` to a render context.
14653     * @method startViewTransform
14654     * @param {render} render
14655     */
14656    Render.startViewTransform = function(render) {
14657        var boundsWidth = render.bounds.max.x - render.bounds.min.x,
14658            boundsHeight = render.bounds.max.y - render.bounds.min.y,
14659            boundsScaleX = boundsWidth / render.options.width,
14660            boundsScaleY = boundsHeight / render.options.height;
14661
14662        render.context.setTransform(
14663            render.options.pixelRatio / boundsScaleX, 0, 0, 
14664            render.options.pixelRatio / boundsScaleY, 0, 0
14665        );
14666        
14667        render.context.translate(-render.bounds.min.x, -render.bounds.min.y);
14668    };
14669
14670    /**
14671     * Resets all transforms on the render context.
14672     * @method endViewTransform
14673     * @param {render} render
14674     */
14675    Render.endViewTransform = function(render) {
14676        render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0);
14677    };
14678
14679    /**
14680     * Renders the given `engine`'s `Matter.World` object.
14681     * This is the entry point for all rendering and should be called every time the scene changes.
14682     * @method world
14683     * @param {render} render
14684     */
14685    Render.world = function(render, time) {
14686        var startTime = Common.now(),
14687            engine = render.engine,
14688            world = engine.world,
14689            canvas = render.canvas,
14690            context = render.context,
14691            options = render.options,
14692            timing = render.timing;
14693
14694        var allBodies = Composite.allBodies(world),
14695            allConstraints = Composite.allConstraints(world),
14696            background = options.wireframes ? options.wireframeBackground : options.background,
14697            bodies = [],
14698            constraints = [],
14699            i;
14700
14701        var event = {
14702            timestamp: engine.timing.timestamp
14703        };
14704
14705        Events.trigger(render, 'beforeRender', event);
14706
14707        // apply background if it has changed
14708        if (render.currentBackground !== background)
14709            _applyBackground(render, background);
14710
14711        // clear the canvas with a transparent fill, to allow the canvas background to show
14712        context.globalCompositeOperation = 'source-in';
14713        context.fillStyle = "transparent";
14714        context.fillRect(0, 0, canvas.width, canvas.height);
14715        context.globalCompositeOperation = 'source-over';
14716
14717        // handle bounds
14718        if (options.hasBounds) {
14719            // filter out bodies that are not in view
14720            for (i = 0; i < allBodies.length; i++) {
14721                var body = allBodies[i];
14722                if (Bounds.overlaps(body.bounds, render.bounds))
14723                    bodies.push(body);
14724            }
14725
14726            // filter out constraints that are not in view
14727            for (i = 0; i < allConstraints.length; i++) {
14728                var constraint = allConstraints[i],
14729                    bodyA = constraint.bodyA,
14730                    bodyB = constraint.bodyB,
14731                    pointAWorld = constraint.pointA,
14732                    pointBWorld = constraint.pointB;
14733
14734                if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);
14735                if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);
14736
14737                if (!pointAWorld || !pointBWorld)
14738                    continue;
14739
14740                if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld))
14741                    constraints.push(constraint);
14742            }
14743
14744            // transform the view
14745            Render.startViewTransform(render);
14746
14747            // update mouse
14748            if (render.mouse) {
14749                Mouse.setScale(render.mouse, {
14750                    x: (render.bounds.max.x - render.bounds.min.x) / render.options.width,
14751                    y: (render.bounds.max.y - render.bounds.min.y) / render.options.height
14752                });
14753
14754                Mouse.setOffset(render.mouse, render.bounds.min);
14755            }
14756        } else {
14757            constraints = allConstraints;
14758            bodies = allBodies;
14759
14760            if (render.options.pixelRatio !== 1) {
14761                render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0);
14762            }
14763        }
14764
14765        if (!options.wireframes || (engine.enableSleeping && options.showSleeping)) {
14766            // fully featured rendering of bodies
14767            Render.bodies(render, bodies, context);
14768        } else {
14769            if (options.showConvexHulls)
14770                Render.bodyConvexHulls(render, bodies, context);
14771
14772            // optimised method for wireframes only
14773            Render.bodyWireframes(render, bodies, context);
14774        }
14775
14776        if (options.showBounds)
14777            Render.bodyBounds(render, bodies, context);
14778
14779        if (options.showAxes || options.showAngleIndicator)
14780            Render.bodyAxes(render, bodies, context);
14781
14782        if (options.showPositions)
14783            Render.bodyPositions(render, bodies, context);
14784
14785        if (options.showVelocity)
14786            Render.bodyVelocity(render, bodies, context);
14787
14788        if (options.showIds)
14789            Render.bodyIds(render, bodies, context);
14790
14791        if (options.showSeparations)
14792            Render.separations(render, engine.pairs.list, context);
14793
14794        if (options.showCollisions)
14795            Render.collisions(render, engine.pairs.list, context);
14796
14797        if (options.showVertexNumbers)
14798            Render.vertexNumbers(render, bodies, context);
14799
14800        if (options.showMousePosition)
14801            Render.mousePosition(render, render.mouse, context);
14802
14803        Render.constraints(constraints, context);
14804
14805        if (options.hasBounds) {
14806            // revert view transforms
14807            Render.endViewTransform(render);
14808        }
14809
14810        Events.trigger(render, 'afterRender', event);
14811
14812        // log the time elapsed computing this update
14813        timing.lastElapsed = Common.now() - startTime;
14814    };
14815
14816    /**
14817     * Renders statistics about the engine and world useful for debugging.
14818     * @private
14819     * @method stats
14820     * @param {render} render
14821     * @param {RenderingContext} context
14822     * @param {Number} time
14823     */
14824    Render.stats = function(render, context, time) {
14825        var engine = render.engine,
14826            world = engine.world,
14827            bodies = Composite.allBodies(world),
14828            parts = 0,
14829            width = 55,
14830            height = 44,
14831            x = 0,
14832            y = 0;
14833        
14834        // count parts
14835        for (var i = 0; i < bodies.length; i += 1) {
14836            parts += bodies[i].parts.length;
14837        }
14838
14839        // sections
14840        var sections = {
14841            'Part': parts,
14842            'Body': bodies.length,
14843            'Cons': Composite.allConstraints(world).length,
14844            'Comp': Composite.allComposites(world).length,
14845            'Pair': engine.pairs.list.length
14846        };
14847
14848        // background
14849        context.fillStyle = '#0e0f19';
14850        context.fillRect(x, y, width * 5.5, height);
14851
14852        context.font = '12px Arial';
14853        context.textBaseline = 'top';
14854        context.textAlign = 'right';
14855
14856        // sections
14857        for (var key in sections) {
14858            var section = sections[key];
14859            // label
14860            context.fillStyle = '#aaa';
14861            context.fillText(key, x + width, y + 8);
14862
14863            // value
14864            context.fillStyle = '#eee';
14865            context.fillText(section, x + width, y + 26);
14866
14867            x += width;
14868        }
14869    };
14870
14871    /**
14872     * Renders engine and render performance information.
14873     * @private
14874     * @method performance
14875     * @param {render} render
14876     * @param {RenderingContext} context
14877     */
14878    Render.performance = function(render, context) {
14879        var engine = render.engine,
14880            timing = render.timing,
14881            deltaHistory = timing.deltaHistory,
14882            elapsedHistory = timing.elapsedHistory,
14883            timestampElapsedHistory = timing.timestampElapsedHistory,
14884            engineDeltaHistory = timing.engineDeltaHistory,
14885            engineUpdatesHistory = timing.engineUpdatesHistory,
14886            engineElapsedHistory = timing.engineElapsedHistory,
14887            lastEngineUpdatesPerFrame = engine.timing.lastUpdatesPerFrame,
14888            lastEngineDelta = engine.timing.lastDelta;
14889        
14890        var deltaMean = _mean(deltaHistory),
14891            elapsedMean = _mean(elapsedHistory),
14892            engineDeltaMean = _mean(engineDeltaHistory),
14893            engineUpdatesMean = _mean(engineUpdatesHistory),
14894            engineElapsedMean = _mean(engineElapsedHistory),
14895            timestampElapsedMean = _mean(timestampElapsedHistory),
14896            rateMean = (timestampElapsedMean / deltaMean) || 0,
14897            neededUpdatesPerFrame = Math.round(deltaMean / lastEngineDelta),
14898            fps = (1000 / deltaMean) || 0;
14899
14900        var graphHeight = 4,
14901            gap = 12,
14902            width = 60,
14903            height = 34,
14904            x = 10,
14905            y = 69;
14906
14907        // background
14908        context.fillStyle = '#0e0f19';
14909        context.fillRect(0, 50, gap * 5 + width * 6 + 22, height);
14910
14911        // show FPS
14912        Render.status(
14913            context, x, y, width, graphHeight, deltaHistory.length, 
14914            Math.round(fps) + ' fps', 
14915            fps / Render._goodFps,
14916            function(i) { return (deltaHistory[i] / deltaMean) - 1; }
14917        );
14918
14919        // show engine delta
14920        Render.status(
14921            context, x + gap + width, y, width, graphHeight, engineDeltaHistory.length,
14922            lastEngineDelta.toFixed(2) + ' dt', 
14923            Render._goodDelta / lastEngineDelta,
14924            function(i) { return (engineDeltaHistory[i] / engineDeltaMean) - 1; }
14925        );
14926
14927        // show engine updates per frame
14928        Render.status(
14929            context, x + (gap + width) * 2, y, width, graphHeight, engineUpdatesHistory.length,
14930            lastEngineUpdatesPerFrame + ' upf', 
14931            Math.pow(Common.clamp((engineUpdatesMean / neededUpdatesPerFrame) || 1, 0, 1), 4),
14932            function(i) { return (engineUpdatesHistory[i] / engineUpdatesMean) - 1; }
14933        );
14934
14935        // show engine update time
14936        Render.status(
14937            context, x + (gap + width) * 3, y, width, graphHeight, engineElapsedHistory.length,
14938            engineElapsedMean.toFixed(2) + ' ut', 
14939            1 - (lastEngineUpdatesPerFrame * engineElapsedMean / Render._goodFps),
14940            function(i) { return (engineElapsedHistory[i] / engineElapsedMean) - 1; }
14941        );
14942
14943        // show render time
14944        Render.status(
14945            context, x + (gap + width) * 4, y, width, graphHeight, elapsedHistory.length,
14946            elapsedMean.toFixed(2) + ' rt', 
14947            1 - (elapsedMean / Render._goodFps),
14948            function(i) { return (elapsedHistory[i] / elapsedMean) - 1; }
14949        );
14950
14951        // show effective speed
14952        Render.status(
14953            context, x + (gap + width) * 5, y, width, graphHeight, timestampElapsedHistory.length, 
14954            rateMean.toFixed(2) + ' x', 
14955            rateMean * rateMean * rateMean,
14956            function(i) { return (((timestampElapsedHistory[i] / deltaHistory[i]) / rateMean) || 0) - 1; }
14957        );
14958    };
14959
14960    /**
14961     * Renders a label, indicator and a chart.
14962     * @private
14963     * @method status
14964     * @param {RenderingContext} context
14965     * @param {number} x
14966     * @param {number} y
14967     * @param {number} width
14968     * @param {number} height
14969     * @param {number} count
14970     * @param {string} label
14971     * @param {string} indicator
14972     * @param {function} plotY
14973     */
14974    Render.status = function(context, x, y, width, height, count, label, indicator, plotY) {
14975        // background
14976        context.strokeStyle = '#888';
14977        context.fillStyle = '#444';
14978        context.lineWidth = 1;
14979        context.fillRect(x, y + 7, width, 1);
14980
14981        // chart
14982        context.beginPath();
14983        context.moveTo(x, y + 7 - height * Common.clamp(0.4 * plotY(0), -2, 2));
14984        for (var i = 0; i < width; i += 1) {
14985            context.lineTo(x + i, y + 7 - (i < count ? height * Common.clamp(0.4 * plotY(i), -2, 2) : 0));
14986        }
14987        context.stroke();
14988
14989        // indicator
14990        context.fillStyle = 'hsl(' + Common.clamp(25 + 95 * indicator, 0, 120) + ',100%,60%)';
14991        context.fillRect(x, y - 7, 4, 4);
14992
14993        // label
14994        context.font = '12px Arial';
14995        context.textBaseline = 'middle';
14996        context.textAlign = 'right';
14997        context.fillStyle = '#eee';
14998        context.fillText(label, x + width, y - 5);
14999    };
15000
15001    /**
15002     * Description
15003     * @private
15004     * @method constraints
15005     * @param {constraint[]} constraints
15006     * @param {RenderingContext} context
15007     */
15008    Render.constraints = function(constraints, context) {
15009        var c = context;
15010
15011        for (var i = 0; i < constraints.length; i++) {
15012            var constraint = constraints[i];
15013
15014            if (!constraint.render.visible || !constraint.pointA || !constraint.pointB)
15015                continue;
15016
15017            var bodyA = constraint.bodyA,
15018                bodyB = constraint.bodyB,
15019                start,
15020                end;
15021
15022            if (bodyA) {
15023                start = Vector.add(bodyA.position, constraint.pointA);
15024            } else {
15025                start = constraint.pointA;
15026            }
15027
15028            if (constraint.render.type === 'pin') {
15029                c.beginPath();
15030                c.arc(start.x, start.y, 3, 0, 2 * Math.PI);
15031                c.closePath();
15032            } else {
15033                if (bodyB) {
15034                    end = Vector.add(bodyB.position, constraint.pointB);
15035                } else {
15036                    end = constraint.pointB;
15037                }
15038
15039                c.beginPath();
15040                c.moveTo(start.x, start.y);
15041
15042                if (constraint.render.type === 'spring') {
15043                    var delta = Vector.sub(end, start),
15044                        normal = Vector.perp(Vector.normalise(delta)),
15045                        coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)),
15046                        offset;
15047
15048                    for (var j = 1; j < coils; j += 1) {
15049                        offset = j % 2 === 0 ? 1 : -1;
15050
15051                        c.lineTo(
15052                            start.x + delta.x * (j / coils) + normal.x * offset * 4,
15053                            start.y + delta.y * (j / coils) + normal.y * offset * 4
15054                        );
15055                    }
15056                }
15057
15058                c.lineTo(end.x, end.y);
15059            }
15060
15061            if (constraint.render.lineWidth) {
15062                c.lineWidth = constraint.render.lineWidth;
15063                c.strokeStyle = constraint.render.strokeStyle;
15064                c.stroke();
15065            }
15066
15067            if (constraint.render.anchors) {
15068                c.fillStyle = constraint.render.strokeStyle;
15069                c.beginPath();
15070                c.arc(start.x, start.y, 3, 0, 2 * Math.PI);
15071                c.arc(end.x, end.y, 3, 0, 2 * Math.PI);
15072                c.closePath();
15073                c.fill();
15074            }
15075        }
15076    };
15077
15078    /**
15079     * Description
15080     * @private
15081     * @method bodies
15082     * @param {render} render
15083     * @param {body[]} bodies
15084     * @param {RenderingContext} context
15085     */
15086    Render.bodies = function(render, bodies, context) {
15087        var c = context,
15088            engine = render.engine,
15089            options = render.options,
15090            showInternalEdges = options.showInternalEdges || !options.wireframes,
15091            body,
15092            part,
15093            i,
15094            k;
15095
15096        for (i = 0; i < bodies.length; i++) {
15097            body = bodies[i];
15098
15099            if (!body.render.visible)
15100                continue;
15101
15102            // handle compound parts
15103            for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
15104                part = body.parts[k];
15105
15106                if (!part.render.visible)
15107                    continue;
15108
15109                if (options.showSleeping && body.isSleeping) {
15110                    c.globalAlpha = 0.5 * part.render.opacity;
15111                } else if (part.render.opacity !== 1) {
15112                    c.globalAlpha = part.render.opacity;
15113                }
15114
15115                if (part.render.sprite && part.render.sprite.texture && !options.wireframes) {
15116                    // part sprite
15117                    var sprite = part.render.sprite,
15118                        texture = _getTexture(render, sprite.texture);
15119
15120                    c.translate(part.position.x, part.position.y);
15121                    c.rotate(part.angle);
15122
15123                    c.drawImage(
15124                        texture,
15125                        texture.width * -sprite.xOffset * sprite.xScale,
15126                        texture.height * -sprite.yOffset * sprite.yScale,
15127                        texture.width * sprite.xScale,
15128                        texture.height * sprite.yScale
15129                    );
15130
15131                    // revert translation, hopefully faster than save / restore
15132                    c.rotate(-part.angle);
15133                    c.translate(-part.position.x, -part.position.y);
15134                } else {
15135                    // part polygon
15136                    if (part.circleRadius) {
15137                        c.beginPath();
15138                        c.arc(part.position.x, part.position.y, part.circleRadius, 0, 2 * Math.PI);
15139                    } else {
15140                        c.beginPath();
15141                        c.moveTo(part.vertices[0].x, part.vertices[0].y);
15142
15143                        for (var j = 1; j < part.vertices.length; j++) {
15144                            if (!part.vertices[j - 1].isInternal || showInternalEdges) {
15145                                c.lineTo(part.vertices[j].x, part.vertices[j].y);
15146                            } else {
15147                                c.moveTo(part.vertices[j].x, part.vertices[j].y);
15148                            }
15149
15150                            if (part.vertices[j].isInternal && !showInternalEdges) {
15151                                c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y);
15152                            }
15153                        }
15154
15155                        c.lineTo(part.vertices[0].x, part.vertices[0].y);
15156                        c.closePath();
15157                    }
15158
15159                    if (!options.wireframes) {
15160                        c.fillStyle = part.render.fillStyle;
15161
15162                        if (part.render.lineWidth) {
15163                            c.lineWidth = part.render.lineWidth;
15164                            c.strokeStyle = part.render.strokeStyle;
15165                            c.stroke();
15166                        }
15167
15168                        c.fill();
15169                    } else {
15170                        c.lineWidth = 1;
15171                        c.strokeStyle = render.options.wireframeStrokeStyle;
15172                        c.stroke();
15173                    }
15174                }
15175
15176                c.globalAlpha = 1;
15177            }
15178        }
15179    };
15180
15181    /**
15182     * Optimised method for drawing body wireframes in one pass
15183     * @private
15184     * @method bodyWireframes
15185     * @param {render} render
15186     * @param {body[]} bodies
15187     * @param {RenderingContext} context
15188     */
15189    Render.bodyWireframes = function(render, bodies, context) {
15190        var c = context,
15191            showInternalEdges = render.options.showInternalEdges,
15192            body,
15193            part,
15194            i,
15195            j,
15196            k;
15197
15198        c.beginPath();
15199
15200        // render all bodies
15201        for (i = 0; i < bodies.length; i++) {
15202            body = bodies[i];
15203
15204            if (!body.render.visible)
15205                continue;
15206
15207            // handle compound parts
15208            for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
15209                part = body.parts[k];
15210
15211                c.moveTo(part.vertices[0].x, part.vertices[0].y);
15212
15213                for (j = 1; j < part.vertices.length; j++) {
15214                    if (!part.vertices[j - 1].isInternal || showInternalEdges) {
15215                        c.lineTo(part.vertices[j].x, part.vertices[j].y);
15216                    } else {
15217                        c.moveTo(part.vertices[j].x, part.vertices[j].y);
15218                    }
15219
15220                    if (part.vertices[j].isInternal && !showInternalEdges) {
15221                        c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y);
15222                    }
15223                }
15224
15225                c.lineTo(part.vertices[0].x, part.vertices[0].y);
15226            }
15227        }
15228
15229        c.lineWidth = 1;
15230        c.strokeStyle = render.options.wireframeStrokeStyle;
15231        c.stroke();
15232    };
15233
15234    /**
15235     * Optimised method for drawing body convex hull wireframes in one pass
15236     * @private
15237     * @method bodyConvexHulls
15238     * @param {render} render
15239     * @param {body[]} bodies
15240     * @param {RenderingContext} context
15241     */
15242    Render.bodyConvexHulls = function(render, bodies, context) {
15243        var c = context,
15244            body,
15245            part,
15246            i,
15247            j,
15248            k;
15249
15250        c.beginPath();
15251
15252        // render convex hulls
15253        for (i = 0; i < bodies.length; i++) {
15254            body = bodies[i];
15255
15256            if (!body.render.visible || body.parts.length === 1)
15257                continue;
15258
15259            c.moveTo(body.vertices[0].x, body.vertices[0].y);
15260
15261            for (j = 1; j < body.vertices.length; j++) {
15262                c.lineTo(body.vertices[j].x, body.vertices[j].y);
15263            }
15264
15265            c.lineTo(body.vertices[0].x, body.vertices[0].y);
15266        }
15267
15268        c.lineWidth = 1;
15269        c.strokeStyle = 'rgba(255,255,255,0.2)';
15270        c.stroke();
15271    };
15272
15273    /**
15274     * Renders body vertex numbers.
15275     * @private
15276     * @method vertexNumbers
15277     * @param {render} render
15278     * @param {body[]} bodies
15279     * @param {RenderingContext} context
15280     */
15281    Render.vertexNumbers = function(render, bodies, context) {
15282        var c = context,
15283            i,
15284            j,
15285            k;
15286
15287        for (i = 0; i < bodies.length; i++) {
15288            var parts = bodies[i].parts;
15289            for (k = parts.length > 1 ? 1 : 0; k < parts.length; k++) {
15290                var part = parts[k];
15291                for (j = 0; j < part.vertices.length; j++) {
15292                    c.fillStyle = 'rgba(255,255,255,0.2)';
15293                    c.fillText(i + '_' + j, part.position.x + (part.vertices[j].x - part.position.x) * 0.8, part.position.y + (part.vertices[j].y - part.position.y) * 0.8);
15294                }
15295            }
15296        }
15297    };
15298
15299    /**
15300     * Renders mouse position.
15301     * @private
15302     * @method mousePosition
15303     * @param {render} render
15304     * @param {mouse} mouse
15305     * @param {RenderingContext} context
15306     */
15307    Render.mousePosition = function(render, mouse, context) {
15308        var c = context;
15309        c.fillStyle = 'rgba(255,255,255,0.8)';
15310        c.fillText(mouse.position.x + '  ' + mouse.position.y, mouse.position.x + 5, mouse.position.y - 5);
15311    };
15312
15313    /**
15314     * Draws body bounds
15315     * @private
15316     * @method bodyBounds
15317     * @param {render} render
15318     * @param {body[]} bodies
15319     * @param {RenderingContext} context
15320     */
15321    Render.bodyBounds = function(render, bodies, context) {
15322        var c = context,
15323            engine = render.engine,
15324            options = render.options;
15325
15326        c.beginPath();
15327
15328        for (var i = 0; i < bodies.length; i++) {
15329            var body = bodies[i];
15330
15331            if (body.render.visible) {
15332                var parts = bodies[i].parts;
15333                for (var j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {
15334                    var part = parts[j];
15335                    c.rect(part.bounds.min.x, part.bounds.min.y, part.bounds.max.x - part.bounds.min.x, part.bounds.max.y - part.bounds.min.y);
15336                }
15337            }
15338        }
15339
15340        if (options.wireframes) {
15341            c.strokeStyle = 'rgba(255,255,255,0.08)';
15342        } else {
15343            c.strokeStyle = 'rgba(0,0,0,0.1)';
15344        }
15345
15346        c.lineWidth = 1;
15347        c.stroke();
15348    };
15349
15350    /**
15351     * Draws body angle indicators and axes
15352     * @private
15353     * @method bodyAxes
15354     * @param {render} render
15355     * @param {body[]} bodies
15356     * @param {RenderingContext} context
15357     */
15358    Render.bodyAxes = function(render, bodies, context) {
15359        var c = context,
15360            engine = render.engine,
15361            options = render.options,
15362            part,
15363            i,
15364            j,
15365            k;
15366
15367        c.beginPath();
15368
15369        for (i = 0; i < bodies.length; i++) {
15370            var body = bodies[i],
15371                parts = body.parts;
15372
15373            if (!body.render.visible)
15374                continue;
15375
15376            if (options.showAxes) {
15377                // render all axes
15378                for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {
15379                    part = parts[j];
15380                    for (k = 0; k < part.axes.length; k++) {
15381                        var axis = part.axes[k];
15382                        c.moveTo(part.position.x, part.position.y);
15383                        c.lineTo(part.position.x + axis.x * 20, part.position.y + axis.y * 20);
15384                    }
15385                }
15386            } else {
15387                for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {
15388                    part = parts[j];
15389                    for (k = 0; k < part.axes.length; k++) {
15390                        // render a single axis indicator
15391                        c.moveTo(part.position.x, part.position.y);
15392                        c.lineTo((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2,
15393                            (part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2);
15394                    }
15395                }
15396            }
15397        }
15398
15399        if (options.wireframes) {
15400            c.strokeStyle = 'indianred';
15401            c.lineWidth = 1;
15402        } else {
15403            c.strokeStyle = 'rgba(255, 255, 255, 0.4)';
15404            c.globalCompositeOperation = 'overlay';
15405            c.lineWidth = 2;
15406        }
15407
15408        c.stroke();
15409        c.globalCompositeOperation = 'source-over';
15410    };
15411
15412    /**
15413     * Draws body positions
15414     * @private
15415     * @method bodyPositions
15416     * @param {render} render
15417     * @param {body[]} bodies
15418     * @param {RenderingContext} context
15419     */
15420    Render.bodyPositions = function(render, bodies, context) {
15421        var c = context,
15422            engine = render.engine,
15423            options = render.options,
15424            body,
15425            part,
15426            i,
15427            k;
15428
15429        c.beginPath();
15430
15431        // render current positions
15432        for (i = 0; i < bodies.length; i++) {
15433            body = bodies[i];
15434
15435            if (!body.render.visible)
15436                continue;
15437
15438            // handle compound parts
15439            for (k = 0; k < body.parts.length; k++) {
15440                part = body.parts[k];
15441                c.arc(part.position.x, part.position.y, 3, 0, 2 * Math.PI, false);
15442                c.closePath();
15443            }
15444        }
15445
15446        if (options.wireframes) {
15447            c.fillStyle = 'indianred';
15448        } else {
15449            c.fillStyle = 'rgba(0,0,0,0.5)';
15450        }
15451        c.fill();
15452
15453        c.beginPath();
15454
15455        // render previous positions
15456        for (i = 0; i < bodies.length; i++) {
15457            body = bodies[i];
15458            if (body.render.visible) {
15459                c.arc(body.positionPrev.x, body.positionPrev.y, 2, 0, 2 * Math.PI, false);
15460                c.closePath();
15461            }
15462        }
15463
15464        c.fillStyle = 'rgba(255,165,0,0.8)';
15465        c.fill();
15466    };
15467
15468    /**
15469     * Draws body velocity
15470     * @private
15471     * @method bodyVelocity
15472     * @param {render} render
15473     * @param {body[]} bodies
15474     * @param {RenderingContext} context
15475     */
15476    Render.bodyVelocity = function(render, bodies, context) {
15477        var c = context;
15478
15479        c.beginPath();
15480
15481        for (var i = 0; i < bodies.length; i++) {
15482            var body = bodies[i];
15483
15484            if (!body.render.visible)
15485                continue;
15486
15487            var velocity = Body.getVelocity(body);
15488
15489            c.moveTo(body.position.x, body.position.y);
15490            c.lineTo(body.position.x + velocity.x, body.position.y + velocity.y);
15491        }
15492
15493        c.lineWidth = 3;
15494        c.strokeStyle = 'cornflowerblue';
15495        c.stroke();
15496    };
15497
15498    /**
15499     * Draws body ids
15500     * @private
15501     * @method bodyIds
15502     * @param {render} render
15503     * @param {body[]} bodies
15504     * @param {RenderingContext} context
15505     */
15506    Render.bodyIds = function(render, bodies, context) {
15507        var c = context,
15508            i,
15509            j;
15510
15511        for (i = 0; i < bodies.length; i++) {
15512            if (!bodies[i].render.visible)
15513                continue;
15514
15515            var parts = bodies[i].parts;
15516            for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {
15517                var part = parts[j];
15518                c.font = "12px Arial";
15519                c.fillStyle = 'rgba(255,255,255,0.5)';
15520                c.fillText(part.id, part.position.x + 10, part.position.y - 10);
15521            }
15522        }
15523    };
15524
15525    /**
15526     * Description
15527     * @private
15528     * @method collisions
15529     * @param {render} render
15530     * @param {pair[]} pairs
15531     * @param {RenderingContext} context
15532     */
15533    Render.collisions = function(render, pairs, context) {
15534        var c = context,
15535            options = render.options,
15536            pair,
15537            collision,
15538            corrected,
15539            bodyA,
15540            bodyB,
15541            i,
15542            j;
15543
15544        c.beginPath();
15545
15546        // render collision positions
15547        for (i = 0; i < pairs.length; i++) {
15548            pair = pairs[i];
15549
15550            if (!pair.isActive)
15551                continue;
15552
15553            collision = pair.collision;
15554            for (j = 0; j < pair.contactCount; j++) {
15555                var contact = pair.contacts[j],
15556                    vertex = contact.vertex;
15557                c.rect(vertex.x - 1.5, vertex.y - 1.5, 3.5, 3.5);
15558            }
15559        }
15560
15561        if (options.wireframes) {
15562            c.fillStyle = 'rgba(255,255,255,0.7)';
15563        } else {
15564            c.fillStyle = 'orange';
15565        }
15566        c.fill();
15567
15568        c.beginPath();
15569
15570        // render collision normals
15571        for (i = 0; i < pairs.length; i++) {
15572            pair = pairs[i];
15573
15574            if (!pair.isActive)
15575                continue;
15576
15577            collision = pair.collision;
15578
15579            if (pair.contactCount > 0) {
15580                var normalPosX = pair.contacts[0].vertex.x,
15581                    normalPosY = pair.contacts[0].vertex.y;
15582
15583                if (pair.contactCount === 2) {
15584                    normalPosX = (pair.contacts[0].vertex.x + pair.contacts[1].vertex.x) / 2;
15585                    normalPosY = (pair.contacts[0].vertex.y + pair.contacts[1].vertex.y) / 2;
15586                }
15587
15588                if (collision.bodyB === collision.supports[0].body || collision.bodyA.isStatic === true) {
15589                    c.moveTo(normalPosX - collision.normal.x * 8, normalPosY - collision.normal.y * 8);
15590                } else {
15591                    c.moveTo(normalPosX + collision.normal.x * 8, normalPosY + collision.normal.y * 8);
15592                }
15593
15594                c.lineTo(normalPosX, normalPosY);
15595            }
15596        }
15597
15598        if (options.wireframes) {
15599            c.strokeStyle = 'rgba(255,165,0,0.7)';
15600        } else {
15601            c.strokeStyle = 'orange';
15602        }
15603
15604        c.lineWidth = 1;
15605        c.stroke();
15606    };
15607
15608    /**
15609     * Description
15610     * @private
15611     * @method separations
15612     * @param {render} render
15613     * @param {pair[]} pairs
15614     * @param {RenderingContext} context
15615     */
15616    Render.separations = function(render, pairs, context) {
15617        var c = context,
15618            options = render.options,
15619            pair,
15620            collision,
15621            corrected,
15622            bodyA,
15623            bodyB,
15624            i,
15625            j;
15626
15627        c.beginPath();
15628
15629        // render separations
15630        for (i = 0; i < pairs.length; i++) {
15631            pair = pairs[i];
15632
15633            if (!pair.isActive)
15634                continue;
15635
15636            collision = pair.collision;
15637            bodyA = collision.bodyA;
15638            bodyB = collision.bodyB;
15639
15640            var k = 1;
15641
15642            if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5;
15643            if (bodyB.isStatic) k = 0;
15644
15645            c.moveTo(bodyB.position.x, bodyB.position.y);
15646            c.lineTo(bodyB.position.x - collision.penetration.x * k, bodyB.position.y - collision.penetration.y * k);
15647
15648            k = 1;
15649
15650            if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5;
15651            if (bodyA.isStatic) k = 0;
15652
15653            c.moveTo(bodyA.position.x, bodyA.position.y);
15654            c.lineTo(bodyA.position.x + collision.penetration.x * k, bodyA.position.y + collision.penetration.y * k);
15655        }
15656
15657        if (options.wireframes) {
15658            c.strokeStyle = 'rgba(255,165,0,0.5)';
15659        } else {
15660            c.strokeStyle = 'orange';
15661        }
15662        c.stroke();
15663    };
15664
15665    /**
15666     * Description
15667     * @private
15668     * @method inspector
15669     * @param {inspector} inspector
15670     * @param {RenderingContext} context
15671     */
15672    Render.inspector = function(inspector, context) {
15673        var engine = inspector.engine,
15674            selected = inspector.selected,
15675            render = inspector.render,
15676            options = render.options,
15677            bounds;
15678
15679        if (options.hasBounds) {
15680            var boundsWidth = render.bounds.max.x - render.bounds.min.x,
15681                boundsHeight = render.bounds.max.y - render.bounds.min.y,
15682                boundsScaleX = boundsWidth / render.options.width,
15683                boundsScaleY = boundsHeight / render.options.height;
15684
15685            context.scale(1 / boundsScaleX, 1 / boundsScaleY);
15686            context.translate(-render.bounds.min.x, -render.bounds.min.y);
15687        }
15688
15689        for (var i = 0; i < selected.length; i++) {
15690            var item = selected[i].data;
15691
15692            context.translate(0.5, 0.5);
15693            context.lineWidth = 1;
15694            context.strokeStyle = 'rgba(255,165,0,0.9)';
15695            context.setLineDash([1,2]);
15696
15697            switch (item.type) {
15698
15699            case 'body':
15700
15701                // render body selections
15702                bounds = item.bounds;
15703                context.beginPath();
15704                context.rect(Math.floor(bounds.min.x - 3), Math.floor(bounds.min.y - 3),
15705                    Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6));
15706                context.closePath();
15707                context.stroke();
15708
15709                break;
15710
15711            case 'constraint':
15712
15713                // render constraint selections
15714                var point = item.pointA;
15715                if (item.bodyA)
15716                    point = item.pointB;
15717                context.beginPath();
15718                context.arc(point.x, point.y, 10, 0, 2 * Math.PI);
15719                context.closePath();
15720                context.stroke();
15721
15722                break;
15723
15724            }
15725
15726            context.setLineDash([]);
15727            context.translate(-0.5, -0.5);
15728        }
15729
15730        // render selection region
15731        if (inspector.selectStart !== null) {
15732            context.translate(0.5, 0.5);
15733            context.lineWidth = 1;
15734            context.strokeStyle = 'rgba(255,165,0,0.6)';
15735            context.fillStyle = 'rgba(255,165,0,0.1)';
15736            bounds = inspector.selectBounds;
15737            context.beginPath();
15738            context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y),
15739                Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y));
15740            context.closePath();
15741            context.stroke();
15742            context.fill();
15743            context.translate(-0.5, -0.5);
15744        }
15745
15746        if (options.hasBounds)
15747            context.setTransform(1, 0, 0, 1, 0, 0);
15748    };
15749
15750    /**
15751     * Updates render timing.
15752     * @method _updateTiming
15753     * @private
15754     * @param {render} render
15755     * @param {number} time
15756     */
15757    var _updateTiming = function(render, time) {
15758        var engine = render.engine,
15759            timing = render.timing,
15760            historySize = timing.historySize,
15761            timestamp = engine.timing.timestamp;
15762
15763        timing.delta = time - timing.lastTime || Render._goodDelta;
15764        timing.lastTime = time;
15765
15766        timing.timestampElapsed = timestamp - timing.lastTimestamp || 0;
15767        timing.lastTimestamp = timestamp;
15768
15769        timing.deltaHistory.unshift(timing.delta);
15770        timing.deltaHistory.length = Math.min(timing.deltaHistory.length, historySize);
15771
15772        timing.engineDeltaHistory.unshift(engine.timing.lastDelta);
15773        timing.engineDeltaHistory.length = Math.min(timing.engineDeltaHistory.length, historySize);
15774
15775        timing.timestampElapsedHistory.unshift(timing.timestampElapsed);
15776        timing.timestampElapsedHistory.length = Math.min(timing.timestampElapsedHistory.length, historySize);
15777
15778        timing.engineUpdatesHistory.unshift(engine.timing.lastUpdatesPerFrame);
15779        timing.engineUpdatesHistory.length = Math.min(timing.engineUpdatesHistory.length, historySize);
15780
15781        timing.engineElapsedHistory.unshift(engine.timing.lastElapsed);
15782        timing.engineElapsedHistory.length = Math.min(timing.engineElapsedHistory.length, historySize);
15783
15784        timing.elapsedHistory.unshift(timing.lastElapsed);
15785        timing.elapsedHistory.length = Math.min(timing.elapsedHistory.length, historySize);
15786    };
15787
15788    /**
15789     * Returns the mean value of the given numbers.
15790     * @method _mean
15791     * @private
15792     * @param {Number[]} values
15793     * @return {Number} the mean of given values
15794     */
15795    var _mean = function(values) {
15796        var result = 0;
15797        for (var i = 0; i < values.length; i += 1) {
15798            result += values[i];
15799        }
15800        return (result / values.length) || 0;
15801    };
15802
15803    /**
15804     * @method _createCanvas
15805     * @private
15806     * @param {} width
15807     * @param {} height
15808     * @return canvas
15809     */
15810    var _createCanvas = function(width, height) {
15811        var canvas = document.createElement('canvas');
15812        canvas.width = width;
15813        canvas.height = height;
15814        canvas.oncontextmenu = function() { return false; };
15815        canvas.onselectstart = function() { return false; };
15816        return canvas;
15817    };
15818
15819    /**
15820     * Gets the pixel ratio of the canvas.
15821     * @method _getPixelRatio
15822     * @private
15823     * @param {HTMLElement} canvas
15824     * @return {Number} pixel ratio
15825     */
15826    var _getPixelRatio = function(canvas) {
15827        var context = canvas.getContext('2d'),
15828            devicePixelRatio = window.devicePixelRatio || 1,
15829            backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio
15830                                      || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio
15831                                      || context.backingStorePixelRatio || 1;
15832
15833        return devicePixelRatio / backingStorePixelRatio;
15834    };
15835
15836    /**
15837     * Gets the requested texture (an Image) via its path
15838     * @method _getTexture
15839     * @private
15840     * @param {render} render
15841     * @param {string} imagePath
15842     * @return {Image} texture
15843     */
15844    var _getTexture = function(render, imagePath) {
15845        var image = render.textures[imagePath];
15846
15847        if (image)
15848            return image;
15849
15850        image = render.textures[imagePath] = new Image();
15851        image.src = imagePath;
15852
15853        return image;
15854    };
15855
15856    /**
15857     * Applies the background to the canvas using CSS.
15858     * @method applyBackground
15859     * @private
15860     * @param {render} render
15861     * @param {string} background
15862     */
15863    var _applyBackground = function(render, background) {
15864        var cssBackground = background;
15865
15866        if (/(jpg|gif|png)$/.test(background))
15867            cssBackground = 'url(' + background + ')';
15868
15869        render.canvas.style.background = cssBackground;
15870        render.canvas.style.backgroundSize = "contain";
15871        render.currentBackground = background;
15872    };
15873
15874    /*
15875    *
15876    *  Events Documentation
15877    *
15878    */
15879
15880    /**
15881    * Fired before rendering
15882    *
15883    * @event beforeRender
15884    * @param {} event An event object
15885    * @param {number} event.timestamp The engine.timing.timestamp of the event
15886    * @param {} event.source The source object of the event
15887    * @param {} event.name The name of the event
15888    */
15889
15890    /**
15891    * Fired after rendering
15892    *
15893    * @event afterRender
15894    * @param {} event An event object
15895    * @param {number} event.timestamp The engine.timing.timestamp of the event
15896    * @param {} event.source The source object of the event
15897    * @param {} event.name The name of the event
15898    */
15899
15900    /*
15901    *
15902    *  Properties Documentation
15903    *
15904    */
15905
15906    /**
15907     * A back-reference to the `Matter.Render` module.
15908     *
15909     * @deprecated
15910     * @property controller
15911     * @type render
15912     */
15913
15914    /**
15915     * A reference to the `Matter.Engine` instance to be used.
15916     *
15917     * @property engine
15918     * @type engine
15919     */
15920
15921    /**
15922     * A reference to the element where the canvas is to be inserted (if `render.canvas` has not been specified)
15923     *
15924     * @property element
15925     * @type HTMLElement
15926     * @default null
15927     */
15928
15929    /**
15930     * The canvas element to render to. If not specified, one will be created if `render.element` has been specified.
15931     *
15932     * @property canvas
15933     * @type HTMLCanvasElement
15934     * @default null
15935     */
15936
15937    /**
15938     * A `Bounds` object that specifies the drawing view region.
15939     * Rendering will be automatically transformed and scaled to fit within the canvas size (`render.options.width` and `render.options.height`).
15940     * This allows for creating views that can pan or zoom around the scene.
15941     * You must also set `render.options.hasBounds` to `true` to enable bounded rendering.
15942     *
15943     * @property bounds
15944     * @type bounds
15945     */
15946
15947    /**
15948     * The 2d rendering context from the `render.canvas` element.
15949     *
15950     * @property context
15951     * @type CanvasRenderingContext2D
15952     */
15953
15954    /**
15955     * The sprite texture cache.
15956     *
15957     * @property textures
15958     * @type {}
15959     */
15960
15961    /**
15962     * The mouse to render if `render.options.showMousePosition` is enabled.
15963     *
15964     * @property mouse
15965     * @type mouse
15966     * @default null
15967     */
15968
15969    /**
15970     * The configuration options of the renderer.
15971     *
15972     * @property options
15973     * @type {}
15974     */
15975
15976    /**
15977     * The target width in pixels of the `render.canvas` to be created.
15978     * See also the `options.pixelRatio` property to change render quality.
15979     *
15980     * @property options.width
15981     * @type number
15982     * @default 800
15983     */
15984
15985    /**
15986     * The target height in pixels of the `render.canvas` to be created.
15987     * See also the `options.pixelRatio` property to change render quality.
15988     *
15989     * @property options.height
15990     * @type number
15991     * @default 600
15992     */
15993
15994    /**
15995     * The [pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) to use when rendering.
15996     *
15997     * @property options.pixelRatio
15998     * @type number
15999     * @default 1
16000     */
16001
16002    /**
16003     * A CSS background color string to use when `render.options.wireframes` is disabled.
16004     * This may be also set to `'transparent'` or equivalent.
16005     *
16006     * @property options.background
16007     * @type string
16008     * @default '#14151f'
16009     */
16010
16011    /**
16012     * A CSS color string to use for background when `render.options.wireframes` is enabled.
16013     * This may be also set to `'transparent'` or equivalent.
16014     *
16015     * @property options.wireframeBackground
16016     * @type string
16017     * @default '#14151f'
16018     */
16019
16020    /**
16021     * A CSS color string to use for stroke when `render.options.wireframes` is enabled.
16022     * This may be also set to `'transparent'` or equivalent.
16023     *
16024     * @property options.wireframeStrokeStyle
16025     * @type string
16026     * @default '#bbb'
16027     */
16028
16029    /**
16030     * A flag that specifies if `render.bounds` should be used when rendering.
16031     *
16032     * @property options.hasBounds
16033     * @type boolean
16034     * @default false
16035     */
16036
16037    /**
16038     * A flag to enable or disable all debug information overlays together.  
16039     * This includes and has priority over the values of:
16040     *
16041     * - `render.options.showStats`
16042     * - `render.options.showPerformance`
16043     *
16044     * @property options.showDebug
16045     * @type boolean
16046     * @default false
16047     */
16048
16049    /**
16050     * A flag to enable or disable the engine stats info overlay.  
16051     * From left to right, the values shown are:
16052     *
16053     * - body parts total
16054     * - body total
16055     * - constraints total
16056     * - composites total
16057     * - collision pairs total
16058     *
16059     * @property options.showStats
16060     * @type boolean
16061     * @default false
16062     */
16063
16064    /**
16065     * A flag to enable or disable performance charts.  
16066     * From left to right, the values shown are:
16067     *
16068     * - average render frequency (e.g. 60 fps)
16069     * - exact engine delta time used for last update (e.g. 16.66ms)
16070     * - average updates per frame (e.g. 1)
16071     * - average engine execution duration (e.g. 5.00ms)
16072     * - average render execution duration (e.g. 0.40ms)
16073     * - average effective play speed (e.g. '1.00x' is 'real-time')
16074     *
16075     * Each value is recorded over a fixed sample of past frames (60 frames).
16076     *
16077     * A chart shown below each value indicates the variance from the average over the sample.
16078     * The more stable or fixed the value is the flatter the chart will appear.
16079     *
16080     * @property options.showPerformance
16081     * @type boolean
16082     * @default false
16083     */
16084    
16085    /**
16086     * A flag to enable or disable rendering entirely.
16087     *
16088     * @property options.enabled
16089     * @type boolean
16090     * @default false
16091     */
16092
16093    /**
16094     * A flag to toggle wireframe rendering otherwise solid fill rendering is used.
16095     *
16096     * @property options.wireframes
16097     * @type boolean
16098     * @default true
16099     */
16100
16101    /**
16102     * A flag to enable or disable sleeping bodies indicators.
16103     *
16104     * @property options.showSleeping
16105     * @type boolean
16106     * @default true
16107     */
16108
16109    /**
16110     * A flag to enable or disable the debug information overlay.
16111     *
16112     * @property options.showDebug
16113     * @type boolean
16114     * @default false
16115     */
16116
16117    /**
16118     * A flag to enable or disable the collision broadphase debug overlay.
16119     *
16120     * @deprecated no longer implemented
16121     * @property options.showBroadphase
16122     * @type boolean
16123     * @default false
16124     */
16125
16126    /**
16127     * A flag to enable or disable the body bounds debug overlay.
16128     *
16129     * @property options.showBounds
16130     * @type boolean
16131     * @default false
16132     */
16133
16134    /**
16135     * A flag to enable or disable the body velocity debug overlay.
16136     *
16137     * @property options.showVelocity
16138     * @type boolean
16139     * @default false
16140     */
16141
16142    /**
16143     * A flag to enable or disable the body collisions debug overlay.
16144     *
16145     * @property options.showCollisions
16146     * @type boolean
16147     * @default false
16148     */
16149
16150    /**
16151     * A flag to enable or disable the collision resolver separations debug overlay.
16152     *
16153     * @property options.showSeparations
16154     * @type boolean
16155     * @default false
16156     */
16157
16158    /**
16159     * A flag to enable or disable the body axes debug overlay.
16160     *
16161     * @property options.showAxes
16162     * @type boolean
16163     * @default false
16164     */
16165
16166    /**
16167     * A flag to enable or disable the body positions debug overlay.
16168     *
16169     * @property options.showPositions
16170     * @type boolean
16171     * @default false
16172     */
16173
16174    /**
16175     * A flag to enable or disable the body angle debug overlay.
16176     *
16177     * @property options.showAngleIndicator
16178     * @type boolean
16179     * @default false
16180     */
16181
16182    /**
16183     * A flag to enable or disable the body and part ids debug overlay.
16184     *
16185     * @property options.showIds
16186     * @type boolean
16187     * @default false
16188     */
16189
16190    /**
16191     * A flag to enable or disable the body vertex numbers debug overlay.
16192     *
16193     * @property options.showVertexNumbers
16194     * @type boolean
16195     * @default false
16196     */
16197
16198    /**
16199     * A flag to enable or disable the body convex hulls debug overlay.
16200     *
16201     * @property options.showConvexHulls
16202     * @type boolean
16203     * @default false
16204     */
16205
16206    /**
16207     * A flag to enable or disable the body internal edges debug overlay.
16208     *
16209     * @property options.showInternalEdges
16210     * @type boolean
16211     * @default false
16212     */
16213
16214    /**
16215     * A flag to enable or disable the mouse position debug overlay.
16216     *
16217     * @property options.showMousePosition
16218     * @type boolean
16219     * @default false
16220     */
16221
16222})();
16223
16224
16225/***/ }),
16226/* 27 */
16227/***/ (function(module, exports, __webpack_require__) {
16228
16229/**
16230* The `Matter.Runner` module is an optional utility that provides a game loop for running a `Matter.Engine` inside a browser environment.
16231* A runner will continuously update a `Matter.Engine` whilst synchronising engine updates with the browser frame rate.
16232* This runner favours a smoother user experience over perfect time keeping.
16233* This runner is optional and is used for development and debugging but could be useful as a starting point for implementing some games and experiences.
16234* Alternatively see `Engine.update` to step the engine directly inside your own game loop implementation as may be needed inside other environments.
16235*
16236* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
16237*
16238* @class Runner
16239*/
16240
16241var Runner = {};
16242
16243module.exports = Runner;
16244
16245var Events = __webpack_require__(5);
16246var Engine = __webpack_require__(17);
16247var Common = __webpack_require__(0);
16248
16249(function() {
16250
16251    Runner._maxFrameDelta = 1000 / 15;
16252    Runner._frameDeltaFallback = 1000 / 60;
16253    Runner._timeBufferMargin = 1.5;
16254    Runner._elapsedNextEstimate = 1;
16255    Runner._smoothingLowerBound = 0.1;
16256    Runner._smoothingUpperBound = 0.9;
16257
16258    /**
16259     * Creates a new Runner. 
16260     * See the properties section below for detailed information on what you can pass via the `options` object.
16261     * @method create
16262     * @param {} options
16263     */
16264    Runner.create = function(options) {
16265        var defaults = {
16266            delta: 1000 / 60,
16267            frameDelta: null,
16268            frameDeltaSmoothing: true,
16269            frameDeltaSnapping: true,
16270            frameDeltaHistory: [],
16271            frameDeltaHistorySize: 100,
16272            frameRequestId: null,
16273            timeBuffer: 0,
16274            timeLastTick: null,
16275            maxUpdates: null,
16276            maxFrameTime: 1000 / 30,
16277            lastUpdatesDeferred: 0,
16278            enabled: true
16279        };
16280
16281        var runner = Common.extend(defaults, options);
16282
16283        // for temporary back compatibility only
16284        runner.fps = 0;
16285
16286        return runner;
16287    };
16288
16289    /**
16290     * Runs a `Matter.Engine` whilst synchronising engine updates with the browser frame rate. 
16291     * See module and properties descriptions for more information on this runner.
16292     * Alternatively see `Engine.update` to step the engine directly inside your own game loop implementation.
16293     * @method run
16294     * @param {runner} runner
16295     * @param {engine} [engine]
16296     * @return {runner} runner
16297     */
16298    Runner.run = function(runner, engine) {
16299        // initial time buffer for the first frame
16300        runner.timeBuffer = Runner._frameDeltaFallback;
16301
16302        (function onFrame(time){
16303            runner.frameRequestId = Runner._onNextFrame(runner, onFrame);
16304
16305            if (time && runner.enabled) {
16306                Runner.tick(runner, engine, time);
16307            }
16308        })();
16309
16310        return runner;
16311    };
16312
16313    /**
16314     * Performs a single runner tick as used inside `Runner.run`.
16315     * See module and properties descriptions for more information on this runner.
16316     * Alternatively see `Engine.update` to step the engine directly inside your own game loop implementation.
16317     * @method tick
16318     * @param {runner} runner
16319     * @param {engine} engine
16320     * @param {number} time
16321     */
16322    Runner.tick = function(runner, engine, time) {
16323        var tickStartTime = Common.now(),
16324            engineDelta = runner.delta,
16325            updateCount = 0;
16326
16327        // find frame delta time since last call
16328        var frameDelta = time - runner.timeLastTick;
16329
16330        // fallback for unusable frame delta values (e.g. 0, NaN, on first frame or long pauses)
16331        if (!frameDelta || !runner.timeLastTick || frameDelta > Math.max(Runner._maxFrameDelta, runner.maxFrameTime)) {
16332            // reuse last accepted frame delta else fallback
16333            frameDelta = runner.frameDelta || Runner._frameDeltaFallback;
16334        }
16335
16336        if (runner.frameDeltaSmoothing) {
16337            // record frame delta over a number of frames
16338            runner.frameDeltaHistory.push(frameDelta);
16339            runner.frameDeltaHistory = runner.frameDeltaHistory.slice(-runner.frameDeltaHistorySize);
16340
16341            // sort frame delta history
16342            var deltaHistorySorted = runner.frameDeltaHistory.slice(0).sort();
16343
16344            // sample a central window to limit outliers
16345            var deltaHistoryWindow = runner.frameDeltaHistory.slice(
16346                deltaHistorySorted.length * Runner._smoothingLowerBound, 
16347                deltaHistorySorted.length * Runner._smoothingUpperBound
16348            );
16349
16350            // take the mean of the central window
16351            var frameDeltaSmoothed = _mean(deltaHistoryWindow);
16352            frameDelta = frameDeltaSmoothed || frameDelta;
16353        }
16354
16355        if (runner.frameDeltaSnapping) {
16356            // snap frame delta to the nearest 1 Hz
16357            frameDelta = 1000 / Math.round(1000 / frameDelta);
16358        }
16359
16360        // update runner values for next call
16361        runner.frameDelta = frameDelta;
16362        runner.timeLastTick = time;
16363
16364        // accumulate elapsed time
16365        runner.timeBuffer += runner.frameDelta;
16366
16367        // limit time buffer size to a single frame of updates
16368        runner.timeBuffer = Common.clamp(
16369            runner.timeBuffer, 0, runner.frameDelta + engineDelta * Runner._timeBufferMargin
16370        );
16371
16372        // reset count of over budget updates
16373        runner.lastUpdatesDeferred = 0;
16374
16375        // get max updates per frame
16376        var maxUpdates = runner.maxUpdates || Math.ceil(runner.maxFrameTime / engineDelta);
16377
16378        // create event object
16379        var event = {
16380            timestamp: engine.timing.timestamp
16381        };
16382
16383        // tick events before update
16384        Events.trigger(runner, 'beforeTick', event);
16385        Events.trigger(runner, 'tick', event);
16386
16387        var updateStartTime = Common.now();
16388
16389        // simulate time elapsed between calls
16390        while (engineDelta > 0 && runner.timeBuffer >= engineDelta * Runner._timeBufferMargin) {
16391            // update the engine
16392            Events.trigger(runner, 'beforeUpdate', event);
16393            Engine.update(engine, engineDelta);
16394            Events.trigger(runner, 'afterUpdate', event);
16395
16396            // consume time simulated from buffer
16397            runner.timeBuffer -= engineDelta;
16398            updateCount += 1;
16399
16400            // find elapsed time during this tick
16401            var elapsedTimeTotal = Common.now() - tickStartTime,
16402                elapsedTimeUpdates = Common.now() - updateStartTime,
16403                elapsedNextEstimate = elapsedTimeTotal + Runner._elapsedNextEstimate * elapsedTimeUpdates / updateCount;
16404
16405            // defer updates if over performance budgets for this frame
16406            if (updateCount >= maxUpdates || elapsedNextEstimate > runner.maxFrameTime) {
16407                runner.lastUpdatesDeferred = Math.round(Math.max(0, (runner.timeBuffer / engineDelta) - Runner._timeBufferMargin));
16408                break;
16409            }
16410        }
16411
16412        // track timing metrics
16413        engine.timing.lastUpdatesPerFrame = updateCount;
16414
16415        // tick events after update
16416        Events.trigger(runner, 'afterTick', event);
16417
16418        // show useful warnings if needed
16419        if (runner.frameDeltaHistory.length >= 100) {
16420            if (runner.lastUpdatesDeferred && Math.round(runner.frameDelta / engineDelta) > maxUpdates) {
16421                Common.warnOnce('Matter.Runner: runner reached runner.maxUpdates, see docs.');
16422            } else if (runner.lastUpdatesDeferred) {
16423                Common.warnOnce('Matter.Runner: runner reached runner.maxFrameTime, see docs.');
16424            }
16425
16426            if (typeof runner.isFixed !== 'undefined') {
16427                Common.warnOnce('Matter.Runner: runner.isFixed is now redundant, see docs.');
16428            }
16429
16430            if (runner.deltaMin || runner.deltaMax) {
16431                Common.warnOnce('Matter.Runner: runner.deltaMin and runner.deltaMax were removed, see docs.');
16432            }
16433
16434            if (runner.fps !== 0) {
16435                Common.warnOnce('Matter.Runner: runner.fps was replaced by runner.delta, see docs.');
16436            }
16437        }
16438    };
16439
16440    /**
16441     * Ends execution of `Runner.run` on the given `runner` by canceling the frame loop.
16442     * Alternatively to temporarily pause the runner, see `runner.enabled`.
16443     * @method stop
16444     * @param {runner} runner
16445     */
16446    Runner.stop = function(runner) {
16447        Runner._cancelNextFrame(runner);
16448    };
16449
16450    /**
16451     * Schedules the `callback` on this `runner` for the next animation frame.
16452     * @private
16453     * @method _onNextFrame
16454     * @param {runner} runner
16455     * @param {function} callback
16456     * @return {number} frameRequestId
16457     */
16458    Runner._onNextFrame = function(runner, callback) {
16459        if (typeof window !== 'undefined' && window.requestAnimationFrame) {
16460            runner.frameRequestId = window.requestAnimationFrame(callback);
16461        } else {
16462            throw new Error('Matter.Runner: missing required global window.requestAnimationFrame.');
16463        }
16464
16465        return runner.frameRequestId;
16466    };
16467
16468    /**
16469     * Cancels the last callback scheduled by `Runner._onNextFrame` on this `runner`.
16470     * @private
16471     * @method _cancelNextFrame
16472     * @param {runner} runner
16473     */
16474    Runner._cancelNextFrame = function(runner) {
16475        if (typeof window !== 'undefined' && window.cancelAnimationFrame) {
16476            window.cancelAnimationFrame(runner.frameRequestId);
16477        } else {
16478            throw new Error('Matter.Runner: missing required global window.cancelAnimationFrame.');
16479        }
16480    };
16481
16482    /**
16483     * Returns the mean of the given numbers.
16484     * @method _mean
16485     * @private
16486     * @param {Number[]} values
16487     * @return {Number} the mean of given values.
16488     */
16489    var _mean = function(values) {
16490        var result = 0,
16491            valuesLength = values.length;
16492
16493        for (var i = 0; i < valuesLength; i += 1) {
16494            result += values[i];
16495        }
16496
16497        return (result / valuesLength) || 0;
16498    };
16499
16500    /*
16501    *
16502    *  Events Documentation
16503    *
16504    */
16505
16506    /**
16507    * Fired once at the start of the browser frame, before any engine updates.
16508    *
16509    * @event beforeTick
16510    * @param {} event An event object
16511    * @param {number} event.timestamp The engine.timing.timestamp of the event
16512    * @param {} event.source The source object of the event
16513    * @param {} event.name The name of the event
16514    */
16515
16516    /**
16517    * Fired once at the start of the browser frame, after `beforeTick`.
16518    *
16519    * @event tick
16520    * @param {} event An event object
16521    * @param {number} event.timestamp The engine.timing.timestamp of the event
16522    * @param {} event.source The source object of the event
16523    * @param {} event.name The name of the event
16524    */
16525
16526    /**
16527    * Fired once at the end of the browser frame, after `beforeTick`, `tick` and after any engine updates.
16528    *
16529    * @event afterTick
16530    * @param {} event An event object
16531    * @param {number} event.timestamp The engine.timing.timestamp of the event
16532    * @param {} event.source The source object of the event
16533    * @param {} event.name The name of the event
16534    */
16535
16536    /**
16537    * Fired before each and every engine update in this browser frame (if any). 
16538    * There may be multiple engine update calls per browser frame (or none) depending on framerate and timestep delta.
16539    *
16540    * @event beforeUpdate
16541    * @param {} event An event object
16542    * @param {number} event.timestamp The engine.timing.timestamp of the event
16543    * @param {} event.source The source object of the event
16544    * @param {} event.name The name of the event
16545    */
16546
16547    /**
16548    * Fired after each and every engine update in this browser frame (if any). 
16549    * There may be multiple engine update calls per browser frame (or none) depending on framerate and timestep delta.
16550    *
16551    * @event afterUpdate
16552    * @param {} event An event object
16553    * @param {number} event.timestamp The engine.timing.timestamp of the event
16554    * @param {} event.source The source object of the event
16555    * @param {} event.name The name of the event
16556    */
16557
16558    /*
16559    *
16560    *  Properties Documentation
16561    *
16562    */
16563
16564    /**
16565     * The fixed timestep size used for `Engine.update` calls in milliseconds, known as `delta`.
16566     * 
16567     * This value is recommended to be `1000 / 60` ms or smaller (i.e. equivalent to at least 60hz).
16568     * 
16569     * Smaller `delta` values provide higher quality results at the cost of performance.
16570     * 
16571     * You should usually avoid changing `delta` during running, otherwise quality may be affected. 
16572     * 
16573     * For smoother frame pacing choose a `delta` that is an even multiple of each display FPS you target, i.e. `1000 / (n * fps)` as this helps distribute an equal number of updates over each display frame.
16574     * 
16575     * For example with a 60 Hz `delta` i.e. `1000 / 60` the runner will on average perform one update per frame on displays running 60 FPS and one update every two frames on displays running 120 FPS, etc.
16576     * 
16577     * Where as e.g. using a 240 Hz `delta` i.e. `1000 / 240` the runner will on average perform four updates per frame on displays running 60 FPS and two updates per frame on displays running 120 FPS, etc.
16578     * 
16579     * Therefore `Runner.run` will call multiple engine updates (or none) as needed to simulate the time elapsed between browser frames. 
16580     * 
16581     * In practice the number of updates in any particular frame may be restricted to respect the runner's performance budgets. These are specified by `runner.maxFrameTime` and `runner.maxUpdates`, see those properties for details.
16582     * 
16583     * @property delta
16584     * @type number
16585     * @default 1000 / 60
16586     */
16587
16588    /**
16589     * A flag that can be toggled to enable or disable tick calls on this runner, therefore pausing engine updates and events while the runner loop remains running.
16590     *
16591     * @property enabled
16592     * @type boolean
16593     * @default true
16594     */
16595
16596    /**
16597     * The accumulated time elapsed that has yet to be simulated in milliseconds.
16598     * This value is clamped within certain limits (see `Runner.tick` code).
16599     *
16600     * @private
16601     * @property timeBuffer
16602     * @type number
16603     * @default 0
16604     */
16605
16606    /**
16607     * The measured time elapsed between the last two browser frames measured in milliseconds.
16608     * This is useful e.g. to estimate the current browser FPS using `1000 / runner.frameDelta`.
16609     *
16610     * @readonly
16611     * @property frameDelta
16612     * @type number
16613     */
16614
16615    /**
16616     * Enables averaging to smooth frame rate measurements and therefore stabilise play rate.
16617     *
16618     * @property frameDeltaSmoothing
16619     * @type boolean
16620     * @default true
16621     */
16622
16623    /**
16624     * Rounds measured browser frame delta to the nearest 1 Hz.
16625     * This option can help smooth frame rate measurements and simplify handling hardware timing differences e.g. 59.94Hz and 60Hz displays.
16626     * For best results you should also round your `runner.delta` equivalent to the nearest 1 Hz.
16627     *
16628     * @property frameDeltaSnapping
16629     * @type boolean
16630     * @default true
16631     */
16632
16633    /**
16634     * A performance budget that limits execution time allowed for this runner per browser frame in milliseconds.
16635     * 
16636     * To calculate the effective browser FPS at which this throttle is applied use `1000 / runner.maxFrameTime`.
16637     * 
16638     * This performance budget is intended to help maintain browser interactivity and help improve framerate recovery during temporary high CPU usage.
16639     * 
16640     * This budget only covers the measured time elapsed executing the functions called in the scope of the runner tick, including `Engine.update` and its related user event callbacks.
16641     * 
16642     * You may also reduce this budget to allow for any significant additional processing you perform on the same thread outside the scope of this runner tick, e.g. rendering time.
16643     * 
16644     * See also `runner.maxUpdates`.
16645     *
16646     * @property maxFrameTime
16647     * @type number
16648     * @default 1000 / 30
16649     */
16650
16651    /**
16652     * An optional limit for maximum engine update count allowed per frame tick in addition to `runner.maxFrameTime`.
16653     * 
16654     * Unless you set a value it is automatically chosen based on `runner.delta` and `runner.maxFrameTime`.
16655     * 
16656     * See also `runner.maxFrameTime`.
16657     * 
16658     * @property maxUpdates
16659     * @type number
16660     * @default null
16661     */
16662
16663    /**
16664     * The timestamp of the last call to `Runner.tick` used to measure `frameDelta`.
16665     *
16666     * @private
16667     * @property timeLastTick
16668     * @type number
16669     * @default 0
16670     */
16671
16672    /**
16673     * The id of the last call to `Runner._onNextFrame`.
16674     *
16675     * @private
16676     * @property frameRequestId
16677     * @type number
16678     * @default null
16679     */
16680
16681})();
16682
16683
16684/***/ }),
16685/* 28 */
16686/***/ (function(module, exports, __webpack_require__) {
16687
16688/**
16689* This module has now been replaced by `Matter.Collision`.
16690*
16691* All usage should be migrated to `Matter.Collision`.
16692* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.
16693*
16694* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.
16695*
16696* @class SAT
16697* @deprecated
16698*/
16699
16700var SAT = {};
16701
16702module.exports = SAT;
16703
16704var Collision = __webpack_require__(8);
16705var Common = __webpack_require__(0);
16706var deprecated = Common.deprecated;
16707
16708(function() {
16709
16710    /**
16711     * Detect collision between two bodies using the Separating Axis Theorem.
16712     * @deprecated replaced by Collision.collides
16713     * @method collides
16714     * @param {body} bodyA
16715     * @param {body} bodyB
16716     * @return {collision} collision
16717     */
16718    SAT.collides = function(bodyA, bodyB) {
16719        return Collision.collides(bodyA, bodyB);
16720    };
16721
16722    deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');
16723
16724})();
16725
16726
16727/***/ }),
16728/* 29 */
16729/***/ (function(module, exports, __webpack_require__) {
16730
16731/**
16732* The `Matter.Svg` module contains methods for converting SVG images into an array of vector points.
16733*
16734* To use this module you also need the SVGPathSeg polyfill: https://github.com/progers/pathseg
16735*
16736* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).
16737*
16738* @class Svg
16739*/
16740
16741var Svg = {};
16742
16743module.exports = Svg;
16744
16745var Bounds = __webpack_require__(1);
16746var Common = __webpack_require__(0);
16747
16748(function() {
16749
16750    /**
16751     * Converts an SVG path into an array of vector points.
16752     * If the input path forms a concave shape, you must decompose the result into convex parts before use.
16753     * See `Bodies.fromVertices` which provides support for this.
16754     * Note that this function is not guaranteed to support complex paths (such as those with holes).
16755     * You must load the `pathseg.js` polyfill on newer browsers.
16756     * @method pathToVertices
16757     * @param {SVGPathElement} path
16758     * @param {Number} [sampleLength=15]
16759     * @return {Vector[]} points
16760     */
16761    Svg.pathToVertices = function(path, sampleLength) {
16762        if (typeof window !== 'undefined' && !('SVGPathSeg' in window)) {
16763            Common.warn('Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.');
16764        }
16765
16766        // https://github.com/wout/svg.topoly.js/blob/master/svg.topoly.js
16767        var i, il, total, point, segment, segments, 
16768            segmentsQueue, lastSegment, 
16769            lastPoint, segmentIndex, points = [],
16770            lx, ly, length = 0, x = 0, y = 0;
16771
16772        sampleLength = sampleLength || 15;
16773
16774        var addPoint = function(px, py, pathSegType) {
16775            // all odd-numbered path types are relative except PATHSEG_CLOSEPATH (1)
16776            var isRelative = pathSegType % 2 === 1 && pathSegType > 1;
16777
16778            // when the last point doesn't equal the current point add the current point
16779            if (!lastPoint || px != lastPoint.x || py != lastPoint.y) {
16780                if (lastPoint && isRelative) {
16781                    lx = lastPoint.x;
16782                    ly = lastPoint.y;
16783                } else {
16784                    lx = 0;
16785                    ly = 0;
16786                }
16787
16788                var point = {
16789                    x: lx + px,
16790                    y: ly + py
16791                };
16792
16793                // set last point
16794                if (isRelative || !lastPoint) {
16795                    lastPoint = point;
16796                }
16797
16798                points.push(point);
16799
16800                x = lx + px;
16801                y = ly + py;
16802            }
16803        };
16804
16805        var addSegmentPoint = function(segment) {
16806            var segType = segment.pathSegTypeAsLetter.toUpperCase();
16807
16808            // skip path ends
16809            if (segType === 'Z') 
16810                return;
16811
16812            // map segment to x and y
16813            switch (segType) {
16814
16815            case 'M':
16816            case 'L':
16817            case 'T':
16818            case 'C':
16819            case 'S':
16820            case 'Q':
16821                x = segment.x;
16822                y = segment.y;
16823                break;
16824            case 'H':
16825                x = segment.x;
16826                break;
16827            case 'V':
16828                y = segment.y;
16829                break;
16830            }
16831
16832            addPoint(x, y, segment.pathSegType);
16833        };
16834
16835        // ensure path is absolute
16836        Svg._svgPathToAbsolute(path);
16837
16838        // get total length
16839        total = path.getTotalLength();
16840
16841        // queue segments
16842        segments = [];
16843        for (i = 0; i < path.pathSegList.numberOfItems; i += 1)
16844            segments.push(path.pathSegList.getItem(i));
16845
16846        segmentsQueue = segments.concat();
16847
16848        // sample through path
16849        while (length < total) {
16850            // get segment at position
16851            segmentIndex = path.getPathSegAtLength(length);
16852            segment = segments[segmentIndex];
16853
16854            // new segment
16855            if (segment != lastSegment) {
16856                while (segmentsQueue.length && segmentsQueue[0] != segment)
16857                    addSegmentPoint(segmentsQueue.shift());
16858
16859                lastSegment = segment;
16860            }
16861
16862            // add points in between when curving
16863            // TODO: adaptive sampling
16864            switch (segment.pathSegTypeAsLetter.toUpperCase()) {
16865
16866            case 'C':
16867            case 'T':
16868            case 'S':
16869            case 'Q':
16870            case 'A':
16871                point = path.getPointAtLength(length);
16872                addPoint(point.x, point.y, 0);
16873                break;
16874
16875            }
16876
16877            // increment by sample value
16878            length += sampleLength;
16879        }
16880
16881        // add remaining segments not passed by sampling
16882        for (i = 0, il = segmentsQueue.length; i < il; ++i)
16883            addSegmentPoint(segmentsQueue[i]);
16884
16885        return points;
16886    };
16887
16888    Svg._svgPathToAbsolute = function(path) {
16889        // http://phrogz.net/convert-svg-path-to-all-absolute-commands
16890        // Copyright (c) Gavin Kistner
16891        // http://phrogz.net/js/_ReuseLicense.txt
16892        // Modifications: tidy formatting and naming
16893        var x0, y0, x1, y1, x2, y2, segs = path.pathSegList,
16894            x = 0, y = 0, len = segs.numberOfItems;
16895
16896        for (var i = 0; i < len; ++i) {
16897            var seg = segs.getItem(i),
16898                segType = seg.pathSegTypeAsLetter;
16899
16900            if (/[MLHVCSQTA]/.test(segType)) {
16901                if ('x' in seg) x = seg.x;
16902                if ('y' in seg) y = seg.y;
16903            } else {
16904                if ('x1' in seg) x1 = x + seg.x1;
16905                if ('x2' in seg) x2 = x + seg.x2;
16906                if ('y1' in seg) y1 = y + seg.y1;
16907                if ('y2' in seg) y2 = y + seg.y2;
16908                if ('x' in seg) x += seg.x;
16909                if ('y' in seg) y += seg.y;
16910
16911                switch (segType) {
16912
16913                case 'm':
16914                    segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i);
16915                    break;
16916                case 'l':
16917                    segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i);
16918                    break;
16919                case 'h':
16920                    segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i);
16921                    break;
16922                case 'v':
16923                    segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i);
16924                    break;
16925                case 'c':
16926                    segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i);
16927                    break;
16928                case 's':
16929                    segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i);
16930                    break;
16931                case 'q':
16932                    segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i);
16933                    break;
16934                case 't':
16935                    segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i);
16936                    break;
16937                case 'a':
16938                    segs.replaceItem(path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i);
16939                    break;
16940                case 'z':
16941                case 'Z':
16942                    x = x0;
16943                    y = y0;
16944                    break;
16945
16946                }
16947            }
16948
16949            if (segType == 'M' || segType == 'm') {
16950                x0 = x;
16951                y0 = y;
16952            }
16953        }
16954    };
16955
16956})();
16957
16958/***/ }),
16959/* 30 */
16960/***/ (function(module, exports, __webpack_require__) {
16961
16962/**
16963* This module has now been replaced by `Matter.Composite`.
16964*
16965* All usage should be migrated to the equivalent functions found on `Matter.Composite`.
16966* For example `World.add(world, body)` now becomes `Composite.add(world, body)`.
16967*
16968* The property `world.gravity` has been moved to `engine.gravity`.
16969*
16970* For back-compatibility purposes this module will remain as a direct alias to `Matter.Composite` in the short term during migration.
16971* Eventually this alias module will be marked as deprecated and then later removed in a future release.
16972*
16973* @class World
16974*/
16975
16976var World = {};
16977
16978module.exports = World;
16979
16980var Composite = __webpack_require__(6);
16981var Common = __webpack_require__(0);
16982
16983(function() {
16984
16985    /**
16986     * See above, aliases for back compatibility only
16987     */
16988    World.create = Composite.create;
16989    World.add = Composite.add;
16990    World.remove = Composite.remove;
16991    World.clear = Composite.clear;
16992    World.addComposite = Composite.addComposite;
16993    World.addBody = Composite.addBody;
16994    World.addConstraint = Composite.addConstraint;
16995
16996})();
16997
16998
16999/***/ })
17000/******/ ]);
17001});
17001
17002/**
17003 * fitty v2.4.2 (beautified + ECMA5-compatible)
17004 * Snugly resizes text to fit its parent container
17005 * Copyright (c) 2023 Rik Schennink
17006 */
17007
17008(function (root, factory) {
17009  if (typeof exports === "object" && typeof module !== "undefined") {
17010    module.exports = factory();
17011  } else if (typeof define === "function" && define.amd) {
17012    define(factory);
17013  } else {
17014    root.fitty = factory();
17015  }
17016})(typeof self !== "undefined" ? self : this, function () {
17017  "use strict";
17018
17019  return function (win) {
17020    if (!win) return;
17021
17022    // -------------------------------------------------------------------------
17023    // Helpers (ES5-safe)
17024    // -------------------------------------------------------------------------
17025
17026    function toArray(list) {
17027      return [].slice.call(list);
17028    }
17029
17030    function extend(target) {
17031      target = target || {};
17032      for (var i = 1; i < arguments.length; i++) {
17033        var src = arguments[i];
17034        if (!src) continue;
17035        for (var k in src) {
17036          if (Object.prototype.hasOwnProperty.call(src, k)) {
17037            target[k] = src[k];
17038          }
17039        }
17040      }
17041      return target;
17042    }
17043
17044    function createCustomEvent(name, detail) {
17045      // CustomEvent is not supported in older browsers, fallback to document.createEvent
17046      try {
17047        return new CustomEvent(name, { detail: detail });
17048      } catch (e) {
17049        var ev = document.createEvent("CustomEvent");
17050        ev.initCustomEvent(name, false, false, detail);
17051        return ev;
17052      }
17053    }
17054
17055    // -------------------------------------------------------------------------
17056    // Internal state
17057    // -------------------------------------------------------------------------
17058
17059    var DIRTY_INIT = 0;
17060    var DIRTY_MUTATION = 1;
17061    var DIRTY_LAYOUT = 2;
17062    var DIRTY_FORCE = 3;
17063
17064    var instances = [];
17065    var rafId = null;
17066
17067    // requestAnimationFrame wrapper
17068    var requestTick =
17069      "requestAnimationFrame" in win
17070        ? function (opts) {
17071            opts = opts || { sync: false };
17072
17073            win.cancelAnimationFrame(rafId);
17074
17075            function run() {
17076              var activeDirty = instances.filter(function (item) {
17077                return item.dirty && item.active;
17078              });
17079              return process(activeDirty);
17080            }
17081
17082            if (opts.sync) return run();
17083
17084            rafId = win.requestAnimationFrame(run);
17085          }
17086        : function () {};
17087
17088    // Marks all instances as dirty (type) and triggers a tick
17089    function markAllDirty(type) {
17090      return function (opts) {
17091        instances.forEach(function (item) {
17092          item.dirty = type;
17093        });
17094        requestTick(opts);
17095      };
17096    }
17097
17098    // Process a batch of instances
17099    function process(batch) {
17100      // Compute styles once
17101      batch
17102        .filter(function (item) {
17103          return !item.styleComputed;
17104        })
17105        .forEach(function (item) {
17106          item.styleComputed = computeStyle(item);
17107        });
17108
17109      // Pre-style test and apply fixes if needed
17110      batch.filter(needsPreStyleFix).forEach(applyStyles);
17111
17112      // Items that need layout recalculation
17113      var toLayout = batch.filter(needsLayout);
17114      toLayout.forEach(calcLayout);
17115      toLayout.forEach(function (item) {
17116        applyStyles(item);
17117        clean(item);
17118      });
17119      toLayout.forEach(dispatchFitEvent);
17120    }
17121
17122    function clean(item) {
17123      item.dirty = DIRTY_INIT;
17124      return item.dirty;
17125    }
17126
17127    function calcLayout(item) {
17128      item.availableWidth = item.element.parentNode.clientWidth;
17129      item.currentWidth = item.element.scrollWidth;
17130
17131      item.previousFontSize = item.currentFontSize;
17132
17133      // Scale font size into [minSize, maxSize]
17134      var scaled = (item.availableWidth / item.currentWidth) * item.previousFontSize;
17135      var clamped = Math.min(Math.max(item.minSize, scaled), item.maxSize);
17136      item.currentFontSize = clamped;
17137
17138      item.whiteSpace =
17139        item.multiLine && item.currentFontSize === item.minSize ? "normal" : "nowrap";
17140    }
17141
17142    function needsLayout(item) {
17143      return (
17144        item.dirty !== DIRTY_LAYOUT ||
17145        (item.dirty === DIRTY_LAYOUT &&
17146          item.element.parentNode.clientWidth !== item.availableWidth)
17147      );
17148    }
17149
17150    function computeStyle(item) {
17151      var cs = win.getComputedStyle(item.element, null);
17152      item.currentFontSize = parseFloat(cs.getPropertyValue("font-size"));
17153      item.display = cs.getPropertyValue("display");
17154      item.whiteSpace = cs.getPropertyValue("white-space");
17155      return true;
17156    }
17157
17158    function needsPreStyleFix(item) {
17159      var changed = false;
17160
17161      if (!item.preStyleTestCompleted) {
17162        // Force a measurable layout for inline elements
17163        if (/inline-/.test(item.display)) {
17164          changed = true;
17165          item.display = "inline-block";
17166        }
17167
17168        // Force nowrap while measuring
17169        if (item.whiteSpace !== "nowrap") {
17170          changed = true;
17171          item.whiteSpace = "nowrap";
17172        }
17173
17174        item.preStyleTestCompleted = true;
17175      }
17176
17177      return changed;
17178    }
17179
17180    function applyStyles(item) {
17181      item.element.style.whiteSpace = item.whiteSpace;
17182      item.element.style.display = item.display;
17183      item.element.style.fontSize = item.currentFontSize + "px";
17184    }
17185
17186    function dispatchFitEvent(item) {
17187      var detail = {
17188        oldValue: item.previousFontSize,
17189        newValue: item.currentFontSize,
17190        scaleFactor: item.currentFontSize / item.previousFontSize
17191      };
17192
17193      item.element.dispatchEvent(createCustomEvent("fit", detail));
17194    }
17195
17196    function onMutation(item, dirtyType) {
17197      return function (opts) {
17198        item.dirty = dirtyType;
17199        if (item.active) requestTick(opts);
17200      };
17201    }
17202
17203    function unsubscribe(item) {
17204      return function () {
17205        instances = instances.filter(function (x) {
17206          return x.element !== item.element;
17207        });
17208
17209        if (item.observeMutations && item.observer) {
17210          item.observer.disconnect();
17211        }
17212
17213        item.element.style.whiteSpace = item.originalStyle.whiteSpace;
17214        item.element.style.display = item.originalStyle.display;
17215        item.element.style.fontSize = item.originalStyle.fontSize;
17216      };
17217    }
17218
17219    function unfreeze(item) {
17220      return function () {
17221        if (!item.active) {
17222          item.active = true;
17223          requestTick();
17224        }
17225      };
17226    }
17227
17228    function freeze(item) {
17229      return function () {
17230        item.active = false;
17231      };
17232    }
17233
17234    function observeMutations(item) {
17235      if (item.observeMutations) {
17236        item.observer = new MutationObserver(onMutation(item, DIRTY_MUTATION));
17237        item.observer.observe(item.element, item.observeMutations);
17238      }
17239    }
17240
17241    // -------------------------------------------------------------------------
17242    // Defaults + public API
17243    // -------------------------------------------------------------------------
17244
17245    var defaults = {
17246      minSize: 16,
17247      maxSize: 512,
17248      multiLine: true,
17249      observeMutations:
17250        "MutationObserver" in win && {
17251          subtree: true,
17252          childList: true,
17253          characterData: true
17254        }
17255    };
17256
17257    var windowDelayTimer = null;
17258
17259    function onWindowResize() {
17260      win.clearTimeout(windowDelayTimer);
17261      windowDelayTimer = win.setTimeout(markAllDirty(DIRTY_LAYOUT), api.observeWindowDelay);
17262    }
17263
17264    var windowEvents = ["resize", "orientationchange"];
17265
17266    function createInstances(elements, options) {
17267      var config = extend({}, defaults, options);
17268
17269      var result = elements.map(function (el) {
17270        var item = extend({}, config, { element: el, active: true });
17271
17272        // Init
17273        item.originalStyle = {
17274          whiteSpace: item.element.style.whiteSpace,
17275          display: item.element.style.display,
17276          fontSize: item.element.style.fontSize
17277        };
17278
17279        observeMutations(item);
17280
17281        item.newbie = true;
17282        item.dirty = true;
17283
17284        instances.push(item);
17285
17286        return {
17287          element: el,
17288          fit: onMutation(item, DIRTY_FORCE),
17289          unfreeze: unfreeze(item),
17290          freeze: freeze(item),
17291          unsubscribe: unsubscribe(item)
17292        };
17293      });
17294
17295      requestTick();
17296      return result;
17297    }
17298
17299    function api(input, options) {
17300      options = options || {};
17301
17302      if (typeof input === "string") {
17303        return createInstances(toArray(document.querySelectorAll(input)), options);
17304      }
17305
17306      // Single element
17307      return createInstances([input], options)[0];
17308    }
17309
17310    // Observe window changes (setter)
17311    Object.defineProperty(api, "observeWindow", {
17312      set: function (enabled) {
17313        var method = (enabled ? "add" : "remove") + "EventListener";
17314        windowEvents.forEach(function (evt) {
17315          win[method](evt, onWindowResize);
17316        });
17317      }
17318    });
17319
17320    api.observeWindow = true;
17321    api.observeWindowDelay = 100;
17322
17323    api.fitAll = markAllDirty(DIRTY_FORCE);
17324
17325    return api;
17326  }(typeof window === "undefined" ? null : window);
17327});
17328"use strict";
17329
17330function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17331function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
17332function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
17333function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
17334function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
17335function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
17336(function (global, factory) {
17337  (typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Lenis = factory());
17338})(void 0, function () {
17339  'use strict';
17340
17341  var version = "1.1.9";
17342
17343  // Clamp a value between a minimum and maximum value
17344  function clamp(min, input, max) {
17345    return Math.max(min, Math.min(input, max));
17346  }
17347
17348  // Linearly interpolate between two values using an amount (0 <= t <= 1)
17349  function lerp(x, y, t) {
17350    return (1 - t) * x + t * y;
17351  }
17352
17353  // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
17354  function damp(x, y, lambda, dt) {
17355    return lerp(x, y, 1 - Math.exp(-lambda * dt));
17356  }
17357
17358  // Calculate the modulo of the dividend and divisor while keeping the result within the same sign as the divisor
17359  // https://anguscroll.com/just/just-modulo
17360  function modulo(n, d) {
17361    return (n % d + d) % d;
17362  }
17363  var Animate = /*#__PURE__*/function () {
17364    function Animate() {
17365      _classCallCheck(this, Animate);
17366      this.isRunning = false;
17367      this.value = 0;
17368      this.from = 0;
17369      this.to = 0;
17370      this.duration = 0;
17371      this.currentTime = 0;
17372    }
17373    _createClass(Animate, [{
17374      key: "advance",
17375      value: function advance(deltaTime) {
17376        var _a;
17377        if (!this.isRunning) return;
17378        var completed = false;
17379        if (this.duration && this.easing) {
17380          this.currentTime += deltaTime;
17381          var linearProgress = clamp(0, this.currentTime / this.duration, 1);
17382          completed = linearProgress >= 1;
17383          var easedProgress = completed ? 1 : this.easing(linearProgress);
17384          this.value = this.from + (this.to - this.from) * easedProgress;
17385        } else if (this.lerp) {
17386          this.value = damp(this.value, this.to, this.lerp * 60, deltaTime);
17387          if (Math.round(this.value) === this.to) {
17388            this.value = this.to;
17389            completed = true;
17390          }
17391        } else {
17392          this.value = this.to;
17393          completed = true;
17394        }
17395        if (completed) {
17396          this.stop();
17397        }
17398        (_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.call(this, this.value, completed);
17399      }
17400    }, {
17401      key: "stop",
17402      value: function stop() {
17403        this.isRunning = false;
17404      }
17405    }, {
17406      key: "fromTo",
17407      value: function fromTo(from, to, _ref) {
17408        var lerp = _ref.lerp,
17409          duration = _ref.duration,
17410          easing = _ref.easing,
17411          onStart = _ref.onStart,
17412          onUpdate = _ref.onUpdate;
17413        this.from = this.value = from;
17414        this.to = to;
17415        this.lerp = lerp;
17416        this.duration = duration;
17417        this.easing = easing;
17418        this.currentTime = 0;
17419        this.isRunning = true;
17420        onStart === null || onStart === void 0 ? void 0 : onStart();
17421        this.onUpdate = onUpdate;
17422      }
17423    }]);
17424    return Animate;
17425  }();
17426  function debounce(callback, delay) {
17427    var timer;
17428    return function () {
17429      var args = arguments;
17430      var context = this;
17431      clearTimeout(timer);
17432      timer = setTimeout(function () {
17433        callback.apply(context, args);
17434      }, delay);
17435    };
17436  }
17437  var Dimensions = /*#__PURE__*/function () {
17438    function Dimensions() {
17439      var _this = this;
17440      var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
17441        wrapper = _ref2.wrapper,
17442        content = _ref2.content,
17443        _ref2$autoResize = _ref2.autoResize,
17444        autoResize = _ref2$autoResize === void 0 ? true : _ref2$autoResize,
17445        _ref2$debounce = _ref2.debounce,
17446        debounceValue = _ref2$debounce === void 0 ? 250 : _ref2$debounce;
17447      _classCallCheck(this, Dimensions);
17448      this.width = 0;
17449      this.height = 0;
17450      this.scrollWidth = 0;
17451      this.scrollHeight = 0;
17452      this.resize = function () {
17453        _this.onWrapperResize();
17454        _this.onContentResize();
17455      };
17456      this.onWrapperResize = function () {
17457        if (_this.wrapper === window) {
17458          _this.width = window.innerWidth;
17459          _this.height = window.innerHeight;
17460        } else if (_this.wrapper instanceof HTMLElement) {
17461          _this.width = _this.wrapper.clientWidth;
17462          _this.height = _this.wrapper.clientHeight;
17463        }
17464      };
17465      this.onContentResize = function () {
17466        if (_this.wrapper === window) {
17467          _this.scrollHeight = _this.content.scrollHeight;
17468          _this.scrollWidth = _this.content.scrollWidth;
17469        } else if (_this.wrapper instanceof HTMLElement) {
17470          _this.scrollHeight = _this.wrapper.scrollHeight;
17471          _this.scrollWidth = _this.wrapper.scrollWidth;
17472        }
17473      };
17474      this.wrapper = wrapper;
17475      this.content = content;
17476      if (autoResize) {
17477        this.debouncedResize = debounce(this.resize, debounceValue);
17478        if (this.wrapper === window) {
17479          window.addEventListener('resize', this.debouncedResize, false);
17480        } else {
17481          this.wrapperResizeObserver = new ResizeObserver(this.debouncedResize);
17482          this.wrapperResizeObserver.observe(this.wrapper);
17483        }
17484        this.contentResizeObserver = new ResizeObserver(this.debouncedResize);
17485        this.contentResizeObserver.observe(this.content);
17486      }
17487      this.resize();
17488    }
17489    _createClass(Dimensions, [{
17490      key: "destroy",
17491      value: function destroy() {
17492        var _a, _b;
17493        (_a = this.wrapperResizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
17494        (_b = this.contentResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
17495        window.removeEventListener('resize', this.debouncedResize, false);
17496      }
17497    }, {
17498      key: "limit",
17499      get: function get() {
17500        return {
17501          x: this.scrollWidth - this.width,
17502          y: this.scrollHeight - this.height
17503        };
17504      }
17505    }]);
17506    return Dimensions;
17507  }();
17508  var Emitter = /*#__PURE__*/function () {
17509    function Emitter() {
17510      _classCallCheck(this, Emitter);
17511      this.events = {};
17512    }
17513    _createClass(Emitter, [{
17514      key: "emit",
17515      value: function emit(event) {
17516        var callbacks = this.events[event] || [];
17517        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
17518          args[_key - 1] = arguments[_key];
17519        }
17520        for (var i = 0, length = callbacks.length; i < length; i++) {
17521          callbacks[i].apply(callbacks, args);
17522        }
17523      }
17524    }, {
17525      key: "on",
17526      value: function on(event, callback) {
17527        var _this2 = this;
17528        var _a;
17529        ((_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.push(callback)) || (this.events[event] = [callback]);
17530        return function () {
17531          var _a;
17532          _this2.events[event] = (_a = _this2.events[event]) === null || _a === void 0 ? void 0 : _a.filter(function (i) {
17533            return callback !== i;
17534          });
17535        };
17536      }
17537    }, {
17538      key: "off",
17539      value: function off(event, callback) {
17540        var _a;
17541        this.events[event] = (_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.filter(function (i) {
17542          return callback !== i;
17543        });
17544      }
17545    }, {
17546      key: "destroy",
17547      value: function destroy() {
17548        this.events = {};
17549      }
17550    }]);
17551    return Emitter;
17552  }();
17553  var LINE_HEIGHT = 100 / 6;
17554  var VirtualScroll = /*#__PURE__*/function () {
17555    function VirtualScroll(element, _ref3) {
17556      var _this3 = this;
17557      var _ref3$wheelMultiplier = _ref3.wheelMultiplier,
17558        wheelMultiplier = _ref3$wheelMultiplier === void 0 ? 1 : _ref3$wheelMultiplier,
17559        _ref3$touchMultiplier = _ref3.touchMultiplier,
17560        touchMultiplier = _ref3$touchMultiplier === void 0 ? 1 : _ref3$touchMultiplier;
17561      _classCallCheck(this, VirtualScroll);
17562      this.lastDelta = {
17563        x: 0,
17564        y: 0
17565      };
17566      this.windowWidth = 0;
17567      this.windowHeight = 0;
17568      this.onTouchStart = function (event) {
17569        var _ref4 = event.targetTouches ? event.targetTouches[0] : event,
17570          clientX = _ref4.clientX,
17571          clientY = _ref4.clientY;
17572        _this3.touchStart.x = clientX;
17573        _this3.touchStart.y = clientY;
17574        _this3.lastDelta = {
17575          x: 0,
17576          y: 0
17577        };
17578        _this3.emitter.emit('scroll', {
17579          deltaX: 0,
17580          deltaY: 0,
17581          event: event
17582        });
17583      };
17584      this.onTouchMove = function (event) {
17585        var _a, _b, _c, _d;
17586        var _ref5 = event.targetTouches ? event.targetTouches[0] : event,
17587          clientX = _ref5.clientX,
17588          clientY = _ref5.clientY;
17589        var deltaX = -(clientX - ((_b = (_a = _this3.touchStart) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0)) * _this3.touchMultiplier;
17590        var deltaY = -(clientY - ((_d = (_c = _this3.touchStart) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0)) * _this3.touchMultiplier;
17591        _this3.touchStart.x = clientX;
17592        _this3.touchStart.y = clientY;
17593        _this3.lastDelta = {
17594          x: deltaX,
17595          y: deltaY
17596        };
17597        _this3.emitter.emit('scroll', {
17598          deltaX: deltaX,
17599          deltaY: deltaY,
17600          event: event
17601        });
17602      };
17603      this.onTouchEnd = function (event) {
17604        _this3.emitter.emit('scroll', {
17605          deltaX: _this3.lastDelta.x,
17606          deltaY: _this3.lastDelta.y,
17607          event: event
17608        });
17609      };
17610      this.onWheel = function (event) {
17611        var deltaX = event.deltaX,
17612          deltaY = event.deltaY,
17613          deltaMode = event.deltaMode;
17614        var multiplierX = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? _this3.windowWidth : 1;
17615        var multiplierY = deltaMode === 1 ? LINE_HEIGHT : deltaMode === 2 ? _this3.windowHeight : 1;
17616        deltaX *= multiplierX;
17617        deltaY *= multiplierY;
17618        deltaX *= _this3.wheelMultiplier;
17619        deltaY *= _this3.wheelMultiplier;
17620        _this3.emitter.emit('scroll', {
17621          deltaX: deltaX,
17622          deltaY: deltaY,
17623          event: event
17624        });
17625      };
17626      this.onWindowResize = function () {
17627        _this3.windowWidth = window.innerWidth;
17628        _this3.windowHeight = window.innerHeight;
17629      };
17630      this.element = element;
17631      this.wheelMultiplier = wheelMultiplier;
17632      this.touchMultiplier = touchMultiplier;
17633      this.touchStart = {
17634        x: null,
17635        y: null
17636      };
17637      this.emitter = new Emitter();
17638      window.addEventListener('resize', this.onWindowResize, false);
17639      this.onWindowResize();
17640      this.element.addEventListener('wheel', this.onWheel, {
17641        passive: false
17642      });
17643      this.element.addEventListener('touchstart', this.onTouchStart, {
17644        passive: false
17645      });
17646      this.element.addEventListener('touchmove', this.onTouchMove, {
17647        passive: false
17648      });
17649      this.element.addEventListener('touchend', this.onTouchEnd, {
17650        passive: false
17651      });
17652    }
17653    _createClass(VirtualScroll, [{
17654      key: "on",
17655      value: function on(event, callback) {
17656        return this.emitter.on(event, callback);
17657      }
17658    }, {
17659      key: "destroy",
17660      value: function destroy() {
17661        this.emitter.destroy();
17662        window.removeEventListener('resize', this.onWindowResize, false);
17663        this.element.removeEventListener('wheel', this.onWheel);
17664        this.element.removeEventListener('touchstart', this.onTouchStart);
17665        this.element.removeEventListener('touchmove', this.onTouchMove);
17666        this.element.removeEventListener('touchend', this.onTouchEnd);
17667      }
17668    }]);
17669    return VirtualScroll;
17670  }();
17671  var Lenis = /*#__PURE__*/function () {
17672    function Lenis() {
17673      var _this4 = this;
17674      var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
17675        _ref6$wrapper = _ref6.wrapper,
17676        wrapper = _ref6$wrapper === void 0 ? window : _ref6$wrapper,
17677        _ref6$content = _ref6.content,
17678        content = _ref6$content === void 0 ? document.documentElement : _ref6$content,
17679        _ref6$wheelEventsTarg = _ref6.wheelEventsTarget,
17680        wheelEventsTarget = _ref6$wheelEventsTarg === void 0 ? wrapper : _ref6$wheelEventsTarg,
17681        _ref6$eventsTarget = _ref6.eventsTarget,
17682        eventsTarget = _ref6$eventsTarget === void 0 ? wheelEventsTarget : _ref6$eventsTarget,
17683        _ref6$smoothWheel = _ref6.smoothWheel,
17684        smoothWheel = _ref6$smoothWheel === void 0 ? true : _ref6$smoothWheel,
17685        _ref6$syncTouch = _ref6.syncTouch,
17686        syncTouch = _ref6$syncTouch === void 0 ? false : _ref6$syncTouch,
17687        _ref6$syncTouchLerp = _ref6.syncTouchLerp,
17688        syncTouchLerp = _ref6$syncTouchLerp === void 0 ? 0.075 : _ref6$syncTouchLerp,
17689        _ref6$touchInertiaMul = _ref6.touchInertiaMultiplier,
17690        touchInertiaMultiplier = _ref6$touchInertiaMul === void 0 ? 35 : _ref6$touchInertiaMul,
17691        duration = _ref6.duration,
17692        _ref6$easing = _ref6.easing,
17693        easing = _ref6$easing === void 0 ? function (t) {
17694          return Math.min(1, 1.001 - Math.pow(2, -10 * t));
17695        } : _ref6$easing,
17696        _ref6$lerp = _ref6.lerp,
17697        lerp = _ref6$lerp === void 0 ? 0.1 : _ref6$lerp,
17698        _ref6$infinite = _ref6.infinite,
17699        infinite = _ref6$infinite === void 0 ? false : _ref6$infinite,
17700        _ref6$orientation = _ref6.orientation,
17701        orientation = _ref6$orientation === void 0 ? 'vertical' : _ref6$orientation,
17702        _ref6$gestureOrientat = _ref6.gestureOrientation,
17703        gestureOrientation = _ref6$gestureOrientat === void 0 ? 'vertical' : _ref6$gestureOrientat,
17704        _ref6$touchMultiplier = _ref6.touchMultiplier,
17705        touchMultiplier = _ref6$touchMultiplier === void 0 ? 1 : _ref6$touchMultiplier,
17706        _ref6$wheelMultiplier = _ref6.wheelMultiplier,
17707        wheelMultiplier = _ref6$wheelMultiplier === void 0 ? 1 : _ref6$wheelMultiplier,
17708        _ref6$autoResize = _ref6.autoResize,
17709        autoResize = _ref6$autoResize === void 0 ? true : _ref6$autoResize,
17710        prevent = _ref6.prevent,
17711        virtualScroll = _ref6.virtualScroll,
17712        _ref6$__experimental_ = _ref6.__experimental__naiveDimensions,
17713        __experimental__naiveDimensions = _ref6$__experimental_ === void 0 ? false : _ref6$__experimental_;
17714      _classCallCheck(this, Lenis);
17715      this.__isScrolling = false;
17716      this.__isStopped = false;
17717      this.__isLocked = false;
17718      this.userData = {};
17719      this.lastVelocity = 0;
17720      this.velocity = 0;
17721      this.direction = 0;
17722      this.onPointerDown = function (event) {
17723        if (event.button === 1) {
17724          _this4.reset();
17725        }
17726      };
17727      this.onVirtualScroll = function (data) {
17728        if (typeof _this4.options.virtualScroll === 'function' && _this4.options.virtualScroll(data) === false) return;
17729        var deltaX = data.deltaX,
17730          deltaY = data.deltaY,
17731          event = data.event;
17732        _this4.emitter.emit('virtual-scroll', {
17733          deltaX: deltaX,
17734          deltaY: deltaY,
17735          event: event
17736        });
17737        if (event.ctrlKey) return;
17738        var isTouch = event.type.includes('touch');
17739        var isWheel = event.type.includes('wheel');
17740        _this4.isTouching = event.type === 'touchstart' || event.type === 'touchmove';
17741        var isTapToStop = _this4.options.syncTouch && isTouch && event.type === 'touchstart' && !_this4.isStopped && !_this4.isLocked;
17742        if (isTapToStop) {
17743          _this4.reset();
17744          return;
17745        }
17746        var isClick = deltaX === 0 && deltaY === 0;
17747        var isUnknownGesture = _this4.options.gestureOrientation === 'vertical' && deltaY === 0 || _this4.options.gestureOrientation === 'horizontal' && deltaX === 0;
17748        if (isClick || isUnknownGesture) {
17749          return;
17750        }
17751        var composedPath = event.composedPath();
17752        composedPath = composedPath.slice(0, composedPath.indexOf(_this4.rootElement));
17753        var prevent = _this4.options.prevent;
17754        if (!!composedPath.find(function (node) {
17755          var _a, _b, _c, _d, _e;
17756          return node instanceof Element && (typeof prevent === 'function' && (prevent === null || prevent === void 0 ? void 0 : prevent(node)) || ((_a = node.hasAttribute) === null || _a === void 0 ? void 0 : _a.call(node, 'data-lenis-prevent')) || isTouch && ((_b = node.hasAttribute) === null || _b === void 0 ? void 0 : _b.call(node, 'data-lenis-prevent-touch')) || isWheel && ((_c = node.hasAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'data-lenis-prevent-wheel')) || ((_d = node.classList) === null || _d === void 0 ? void 0 : _d.contains('lenis')) && !((_e = node.classList) === null || _e === void 0 ? void 0 : _e.contains('lenis-stopped')));
17757        })) return;
17758        if (_this4.isStopped || _this4.isLocked) {
17759          event.preventDefault();
17760          return;
17761        }
17762        var isSmooth = _this4.options.syncTouch && isTouch || _this4.options.smoothWheel && isWheel;
17763        if (!isSmooth) {
17764          _this4.isScrolling = 'native';
17765          _this4.animate.stop();
17766          return;
17767        }
17768        event.preventDefault();
17769        var delta = deltaY;
17770        if (_this4.options.gestureOrientation === 'both') {
17771          delta = Math.abs(deltaY) > Math.abs(deltaX) ? deltaY : deltaX;
17772        } else if (_this4.options.gestureOrientation === 'horizontal') {
17773          delta = deltaX;
17774        }
17775        var syncTouch = isTouch && _this4.options.syncTouch;
17776        var isTouchEnd = isTouch && event.type === 'touchend';
17777        var hasTouchInertia = isTouchEnd && Math.abs(delta) > 5;
17778        if (hasTouchInertia) {
17779          delta = _this4.velocity * _this4.options.touchInertiaMultiplier;
17780        }
17781        _this4.scrollTo(_this4.targetScroll + delta, Object.assign({
17782          programmatic: false
17783        }, syncTouch ? {
17784          lerp: hasTouchInertia ? _this4.options.syncTouchLerp : 1
17785        } : {
17786          lerp: _this4.options.lerp,
17787          duration: _this4.options.duration,
17788          easing: _this4.options.easing
17789        }));
17790      };
17791      this.onNativeScroll = function () {
17792        clearTimeout(_this4.__resetVelocityTimeout);
17793        delete _this4.__resetVelocityTimeout;
17794        if (_this4.__preventNextNativeScrollEvent) {
17795          delete _this4.__preventNextNativeScrollEvent;
17796          return;
17797        }
17798        if (_this4.isScrolling === false || _this4.isScrolling === 'native') {
17799          var lastScroll = _this4.animatedScroll;
17800          _this4.animatedScroll = _this4.targetScroll = _this4.actualScroll;
17801          _this4.lastVelocity = _this4.velocity;
17802          _this4.velocity = _this4.animatedScroll - lastScroll;
17803          _this4.direction = Math.sign(_this4.animatedScroll - lastScroll);
17804          _this4.isScrolling = 'native';
17805          _this4.emit();
17806          if (_this4.velocity !== 0) {
17807            _this4.__resetVelocityTimeout = setTimeout(function () {
17808              _this4.lastVelocity = _this4.velocity;
17809              _this4.velocity = 0;
17810              _this4.isScrolling = false;
17811              _this4.emit();
17812            }, 400);
17813          }
17814        }
17815      };
17816      window.lenisVersion = version;
17817      if (!wrapper || wrapper === document.documentElement || wrapper === document.body) {
17818        wrapper = window;
17819      }
17820      this.options = {
17821        wrapper: wrapper,
17822        content: content,
17823        wheelEventsTarget: wheelEventsTarget,
17824        eventsTarget: eventsTarget,
17825        smoothWheel: smoothWheel,
17826        syncTouch: syncTouch,
17827        syncTouchLerp: syncTouchLerp,
17828        touchInertiaMultiplier: touchInertiaMultiplier,
17829        duration: duration,
17830        easing: easing,
17831        lerp: lerp,
17832        infinite: infinite,
17833        gestureOrientation: gestureOrientation,
17834        orientation: orientation,
17835        touchMultiplier: touchMultiplier,
17836        wheelMultiplier: wheelMultiplier,
17837        autoResize: autoResize,
17838        prevent: prevent,
17839        virtualScroll: virtualScroll,
17840        __experimental__naiveDimensions: __experimental__naiveDimensions
17841      };
17842      this.animate = new Animate();
17843      this.emitter = new Emitter();
17844      this.dimensions = new Dimensions({
17845        wrapper: wrapper,
17846        content: content,
17847        autoResize: autoResize
17848      });
17849      this.updateClassName();
17850      this.userData = {};
17851      this.time = 0;
17852      this.velocity = this.lastVelocity = 0;
17853      this.isLocked = false;
17854      this.isStopped = false;
17855      this.isScrolling = false;
17856      this.targetScroll = this.animatedScroll = this.actualScroll;
17857      this.options.wrapper.addEventListener('scroll', this.onNativeScroll, false);
17858      this.options.wrapper.addEventListener('pointerdown', this.onPointerDown, false);
17859      this.virtualScroll = new VirtualScroll(eventsTarget, {
17860        touchMultiplier: touchMultiplier,
17861        wheelMultiplier: wheelMultiplier
17862      });
17863      this.virtualScroll.on('scroll', this.onVirtualScroll);
17864    }
17865    _createClass(Lenis, [{
17866      key: "destroy",
17867      value: function destroy() {
17868        this.emitter.destroy();
17869        this.options.wrapper.removeEventListener('scroll', this.onNativeScroll, false);
17870        this.options.wrapper.removeEventListener('pointerdown', this.onPointerDown, false);
17871        this.virtualScroll.destroy();
17872        this.dimensions.destroy();
17873        this.cleanUpClassName();
17874      }
17875    }, {
17876      key: "on",
17877      value: function on(event, callback) {
17878        return this.emitter.on(event, callback);
17879      }
17880    }, {
17881      key: "off",
17882      value: function off(event, callback) {
17883        return this.emitter.off(event, callback);
17884      }
17885    }, {
17886      key: "setScroll",
17887      value: function setScroll(scroll) {
17888        if (this.isHorizontal) {
17889          this.rootElement.scrollLeft = scroll;
17890        } else {
17891          this.rootElement.scrollTop = scroll;
17892        }
17893      }
17894    }, {
17895      key: "resize",
17896      value: function resize() {
17897        this.dimensions.resize();
17898      }
17899    }, {
17900      key: "emit",
17901      value: function emit() {
17902        this.emitter.emit('scroll', this);
17903      }
17904    }, {
17905      key: "reset",
17906      value: function reset() {
17907        this.isLocked = false;
17908        this.isScrolling = false;
17909        this.animatedScroll = this.targetScroll = this.actualScroll;
17910        this.lastVelocity = this.velocity = 0;
17911        this.animate.stop();
17912      }
17913    }, {
17914      key: "start",
17915      value: function start() {
17916        if (!this.isStopped) return;
17917        this.isStopped = false;
17918        this.reset();
17919      }
17920    }, {
17921      key: "stop",
17922      value: function stop() {
17923        if (this.isStopped) return;
17924        this.isStopped = true;
17925        this.animate.stop();
17926        this.reset();
17927      }
17928    }, {
17929      key: "raf",
17930      value: function raf(time) {
17931        var deltaTime = time - (this.time || time);
17932        this.time = time;
17933        this.animate.advance(deltaTime * 0.001);
17934      }
17935    }, {
17936      key: "scrollTo",
17937      value: function scrollTo(target) {
17938        var _this5 = this;
17939        var _ref7 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
17940          _ref7$offset = _ref7.offset,
17941          offset = _ref7$offset === void 0 ? 0 : _ref7$offset,
17942          _ref7$immediate = _ref7.immediate,
17943          immediate = _ref7$immediate === void 0 ? false : _ref7$immediate,
17944          _ref7$lock = _ref7.lock,
17945          lock = _ref7$lock === void 0 ? false : _ref7$lock,
17946          _ref7$duration = _ref7.duration,
17947          duration = _ref7$duration === void 0 ? this.options.duration : _ref7$duration,
17948          _ref7$easing = _ref7.easing,
17949          easing = _ref7$easing === void 0 ? this.options.easing : _ref7$easing,
17950          _ref7$lerp = _ref7.lerp,
17951          lerp = _ref7$lerp === void 0 ? this.options.lerp : _ref7$lerp,
17952          _onStart = _ref7.onStart,
17953          onComplete = _ref7.onComplete,
17954          _ref7$force = _ref7.force,
17955          force = _ref7$force === void 0 ? false : _ref7$force,
17956          _ref7$programmatic = _ref7.programmatic,
17957          programmatic = _ref7$programmatic === void 0 ? true : _ref7$programmatic,
17958          _ref7$userData = _ref7.userData,
17959          userData = _ref7$userData === void 0 ? {} : _ref7$userData;
17960        if ((this.isStopped || this.isLocked) && !force) return;
17961        if (typeof target === 'string' && ['top', 'left', 'start'].includes(target)) {
17962          target = 0;
17963        } else if (typeof target === 'string' && ['bottom', 'right', 'end'].includes(target)) {
17964          target = this.limit;
17965        } else {
17966          var node;
17967          if (typeof target === 'string') {
17968            node = document.querySelector(target);
17969          } else if (target instanceof HTMLElement && (target === null || target === void 0 ? void 0 : target.nodeType)) {
17970            node = target;
17971          }
17972          if (node) {
17973            if (this.options.wrapper !== window) {
17974              var wrapperRect = this.rootElement.getBoundingClientRect();
17975              offset -= this.isHorizontal ? wrapperRect.left : wrapperRect.top;
17976            }
17977            var rect = node.getBoundingClientRect();
17978            target = (this.isHorizontal ? rect.left : rect.top) + this.animatedScroll;
17979          }
17980        }
17981        if (typeof target !== 'number') return;
17982        target += offset;
17983        target = Math.round(target);
17984        if (this.options.infinite) {
17985          if (programmatic) {
17986            this.targetScroll = this.animatedScroll = this.scroll;
17987          }
17988        } else {
17989          target = clamp(0, target, this.limit);
17990        }
17991        if (target === this.targetScroll) return;
17992        this.userData = userData;
17993        if (immediate) {
17994          this.animatedScroll = this.targetScroll = target;
17995          this.setScroll(this.scroll);
17996          this.reset();
17997          this.preventNextNativeScrollEvent();
17998          this.emit();
17999          onComplete === null || onComplete === void 0 ? void 0 : onComplete(this);
18000          this.userData = {};
18001          return;
18002        }
18003        if (!programmatic) {
18004          this.targetScroll = target;
18005        }
18006        this.animate.fromTo(this.animatedScroll, target, {
18007          duration: duration,
18008          easing: easing,
18009          lerp: lerp,
18010          onStart: function onStart() {
18011            if (lock) _this5.isLocked = true;
18012            _this5.isScrolling = 'smooth';
18013            _onStart === null || _onStart === void 0 ? void 0 : _onStart(_this5);
18014          },
18015          onUpdate: function onUpdate(value, completed) {
18016            _this5.isScrolling = 'smooth';
18017            _this5.lastVelocity = _this5.velocity;
18018            _this5.velocity = value - _this5.animatedScroll;
18019            _this5.direction = Math.sign(_this5.velocity);
18020            _this5.animatedScroll = value;
18021            _this5.setScroll(_this5.scroll);
18022            if (programmatic) {
18023              _this5.targetScroll = value;
18024            }
18025            if (!completed) _this5.emit();
18026            if (completed) {
18027              _this5.reset();
18028              _this5.emit();
18029              onComplete === null || onComplete === void 0 ? void 0 : onComplete(_this5);
18030              _this5.userData = {};
18031              _this5.preventNextNativeScrollEvent();
18032            }
18033          }
18034        });
18035      }
18036    }, {
18037      key: "preventNextNativeScrollEvent",
18038      value: function preventNextNativeScrollEvent() {
18039        var _this6 = this;
18040        this.__preventNextNativeScrollEvent = true;
18041        requestAnimationFrame(function () {
18042          delete _this6.__preventNextNativeScrollEvent;
18043        });
18044      }
18045    }, {
18046      key: "rootElement",
18047      get: function get() {
18048        return this.options.wrapper === window ? document.documentElement : this.options.wrapper;
18049      }
18050    }, {
18051      key: "limit",
18052      get: function get() {
18053        if (this.options.__experimental__naiveDimensions) {
18054          if (this.isHorizontal) {
18055            return this.rootElement.scrollWidth - this.rootElement.clientWidth;
18056          } else {
18057            return this.rootElement.scrollHeight - this.rootElement.clientHeight;
18058          }
18059        } else {
18060          return this.dimensions.limit[this.isHorizontal ? 'x' : 'y'];
18061        }
18062      }
18063    }, {
18064      key: "isHorizontal",
18065      get: function get() {
18066        return this.options.orientation === 'horizontal';
18067      }
18068    }, {
18069      key: "actualScroll",
18070      get: function get() {
18071        return this.isHorizontal ? this.rootElement.scrollLeft : this.rootElement.scrollTop;
18072      }
18073    }, {
18074      key: "scroll",
18075      get: function get() {
18076        return this.options.infinite ? modulo(this.animatedScroll, this.limit) : this.animatedScroll;
18077      }
18078    }, {
18079      key: "progress",
18080      get: function get() {
18081        return this.limit === 0 ? 1 : this.scroll / this.limit;
18082      }
18083    }, {
18084      key: "isScrolling",
18085      get: function get() {
18086        return this.__isScrolling;
18087      },
18088      set: function set(value) {
18089        if (this.__isScrolling !== value) {
18090          this.__isScrolling = value;
18091          this.updateClassName();
18092        }
18093      }
18094    }, {
18095      key: "isStopped",
18096      get: function get() {
18097        return this.__isStopped;
18098      },
18099      set: function set(value) {
18100        if (this.__isStopped !== value) {
18101          this.__isStopped = value;
18102          this.updateClassName();
18103        }
18104      }
18105    }, {
18106      key: "isLocked",
18107      get: function get() {
18108        return this.__isLocked;
18109      },
18110      set: function set(value) {
18111        if (this.__isLocked !== value) {
18112          this.__isLocked = value;
18113          this.updateClassName();
18114        }
18115      }
18116    }, {
18117      key: "isSmooth",
18118      get: function get() {
18119        return this.isScrolling === 'smooth';
18120      }
18121    }, {
18122      key: "className",
18123      get: function get() {
18124        var className = 'lenis';
18125        if (this.isStopped) className += ' lenis-stopped';
18126        if (this.isLocked) className += ' lenis-locked';
18127        if (this.isScrolling) className += ' lenis-scrolling';
18128        if (this.isScrolling === 'smooth') className += ' lenis-smooth';
18129        return className;
18130      }
18131    }, {
18132      key: "updateClassName",
18133      value: function updateClassName() {
18134        this.cleanUpClassName();
18135        this.rootElement.className = "".concat(this.rootElement.className, " ").concat(this.className).trim();
18136      }
18137    }, {
18138      key: "cleanUpClassName",
18139      value: function cleanUpClassName() {
18140        this.rootElement.className = this.rootElement.className.replace(/lenis(-\w+)?/g, '').trim();
18141      }
18142    }]);
18143    return Lenis;
18144  }();
18145  return Lenis;
18146});
18147(function(window, $) {
18148  "use strict";
18149
18150  var counter = 0,
18151    $headCache = $('head'),
18152    oldBigText = window.BigText,
18153    oldjQueryMethod = $.fn.bigtext,
18154    BigText = {
18155      DEBUG_MODE: false,
18156      DEFAULT_MIN_FONT_SIZE_PX: null,
18157      DEFAULT_MAX_FONT_SIZE_PX: 1056,
18158      GLOBAL_STYLE_ID: 'bigtext-style',
18159      STYLE_ID: 'bigtext-id',
18160      LINE_CLASS_PREFIX: 'bigtext-line',
18161      EXEMPT_CLASS: 'bigtext-exempt',
18162      noConflict: function(restore)
18163      {
18164        if(restore) {
18165          $.fn.bigtext = oldjQueryMethod;
18166          window.BigText = oldBigText;
18167        }
18168        return BigText;
18169      },
18170      supports: {
18171        wholeNumberFontSizeOnly: (function() {
18172          if( !( 'getComputedStyle' in window ) ) {
18173            return true;
18174          }
18175          var test = $('<div/>').css({
18176              position: 'absolute',
18177              'font-size': '14.1px'
18178            }).insertBefore( $('script').eq(0) ),
18179            computedStyle = window.getComputedStyle( test[0], null );
18180
18181          var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
18182          test.remove();
18183          return ret;
18184        })()
18185      },
18186      init: function() {
18187        if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
18188          $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
18189                                          '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
18190        }
18191      },
18192      bindResize: function(eventName, resizeFunction) {
18193        var timeoutId;
18194        $(window).off(eventName).on(eventName, function() {
18195          if( timeoutId ) {
18196            clearTimeout( timeoutId );
18197          }
18198          timeoutId = setTimeout( resizeFunction, 100 );
18199        });
18200      },
18201      getStyleId: function(id)
18202      {
18203        return BigText.STYLE_ID + '-' + id;
18204      },
18205      generateStyleTag: function(id, css)
18206      {
18207        return $('<style>' + css.join('\n') + '</style>').attr('id', id);
18208      },
18209      clearCss: function(id)
18210      {
18211        var styleId = BigText.getStyleId(id);
18212        $('#' + styleId).remove();
18213      },
18214      generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
18215      {
18216        var css = [];
18217
18218        BigText.clearCss(id);
18219
18220        for(var j=0, k=linesFontSizes.length; j<k; j++) {
18221          css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
18222            (minFontSizes[j] ? ' white-space: normal;' : '') +
18223            (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
18224            (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
18225            '}');
18226        }
18227
18228        return BigText.generateStyleTag(BigText.getStyleId(id), css);
18229      },
18230      jQueryMethod: function(options)
18231      {
18232        BigText.init();
18233
18234        options = $.extend({
18235          minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
18236          maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
18237          childSelector: '',
18238          resize: true
18239        }, options || {});
18240
18241        this.each(function()
18242        {
18243          var $t = $(this).addClass('bigtext'),
18244            maxWidth = $t.width(),
18245            id = $t.attr('id'),
18246            $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();
18247
18248          if(!id) {
18249            id = 'bigtext-id' + (counter++);
18250            $t.attr('id', id);
18251          }
18252
18253          if(options.resize) {
18254            BigText.bindResize('resize.bigtext-event-' + id, function()
18255            {
18256              // TODO only call this if the width has changed.
18257              BigText.jQueryMethod.call($('#' + id), options);
18258            });
18259          }
18260
18261          BigText.clearCss(id);
18262
18263          $children.addClass(function(lineNumber, className)
18264          {
18265            // remove existing line classes.
18266            return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
18267                BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
18268          });
18269
18270          var sizes = BigText.calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
18271          $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
18272        });
18273
18274        return this.trigger('bigtext:complete');
18275      },
18276      testLineDimensions: function($line, maxWidth, property, size, interval, units, previousWidth)
18277      {
18278        var width;
18279        previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
18280        $line.css(property, size + units);
18281
18282        width = $line.width();
18283
18284        if(width >= maxWidth) {
18285    // console.log(width, ' previous: ' + previousWidth, property + ' at ' + interval, 'prior: ' + (parseFloat(size) - interval), 'new:' + parseFloat(size));
18286          $line.css(property, '');
18287
18288          if(width === maxWidth) {
18289            return {
18290              match: 'exact',
18291              size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
18292            };
18293          }
18294
18295          // Since this is an estimate, we calculate how far over the width we went with the new value.
18296          // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
18297          // Otherwise, we revert to the underestimate.
18298          var under = maxWidth - previousWidth,
18299            over = width - maxWidth;
18300
18301          return {
18302            match: 'estimate',
18303            size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
18304          };
18305        }
18306
18307        return width;
18308      },
18309      calculateSizes: function($t, $children, maxWidth, maxFontSize, minFontSize)
18310      {
18311        var $c = $t.clone(true)
18312          .addClass('bigtext-cloned')
18313          .css({
18314            fontFamily: $t.css('font-family'),
18315            textTransform: $t.css('text-transform'),
18316            wordSpacing: $t.css('word-spacing'),
18317            letterSpacing: $t.css('letter-spacing'),
18318            position: 'absolute',
18319            left: BigText.DEBUG_MODE ? 0 : -9999,
18320            top: BigText.DEBUG_MODE ? 0 : -9999
18321          })
18322          .appendTo(document.body);
18323
18324        // font-size isn't the only thing we can modify, we can also mess with:
18325        // word-spacing and letter-spacing. WebKit does not respect subpixel
18326        // letter-spacing, word-spacing, or font-size.
18327        // TODO try -webkit-transform: scale() as a workaround.
18328        var fontSizes = [],
18329          wordSpacings = [],
18330          minFontSizes = [],
18331          ratios = [];
18332
18333        $children.css('float', 'left').each(function() {
18334          var $line = $(this),
18335            // TODO replace 8, 4 with a proportional size to the calculated font-size.
18336            intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
18337            lineMax,
18338            newFontSize;
18339
18340          if($line.hasClass(BigText.EXEMPT_CLASS)) {
18341            fontSizes.push(null);
18342            ratios.push(null);
18343            minFontSizes.push(false);
18344            return;
18345          }
18346
18347          // TODO we can cache this ratio?
18348          var autoGuessSubtraction = 32, // font size in px
18349            currentFontSize = parseFloat($line.css('font-size')),
18350            ratio = ( $line.width() / currentFontSize ).toFixed(6);
18351
18352          newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;
18353
18354          outer: for(var m=0, n=intervals.length; m<n; m++) {
18355            inner: for(var j=1, k=10; j<=k; j++) {
18356              if(newFontSize + j*intervals[m] > maxFontSize) {
18357                newFontSize = maxFontSize;
18358                break outer;
18359              }
18360
18361              lineMax = BigText.testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
18362              if(typeof lineMax !== 'number') {
18363                newFontSize = lineMax.size;
18364
18365                if(lineMax.match === 'exact') {
18366                  break outer;
18367                }
18368                break inner;
18369              }
18370            }
18371          }
18372
18373          ratios.push(maxWidth / newFontSize);
18374
18375          if(newFontSize > maxFontSize) {
18376            fontSizes.push(maxFontSize);
18377            minFontSizes.push(false);
18378          } else if(!!minFontSize && newFontSize < minFontSize) {
18379            fontSizes.push(minFontSize);
18380            minFontSizes.push(true);
18381          } else {
18382            fontSizes.push(newFontSize);
18383            minFontSizes.push(false);
18384          }
18385        }).each(function(lineNumber) {
18386          var $line = $(this),
18387            wordSpacing = 0,
18388            interval = 1,
18389            maxWordSpacing;
18390
18391          if($line.hasClass(BigText.EXEMPT_CLASS)) {
18392            wordSpacings.push(null);
18393            return;
18394          }
18395
18396          // must re-use font-size, even though it was removed above.
18397          $line.css('font-size', fontSizes[lineNumber] + 'px');
18398
18399          for(var m=1, n=3; m<n; m+=interval) {
18400            maxWordSpacing = BigText.testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
18401            if(typeof maxWordSpacing !== 'number') {
18402              wordSpacing = maxWordSpacing.size;
18403              break;
18404            }
18405          }
18406
18407          $line.css('font-size', '');
18408          wordSpacings.push(wordSpacing);
18409        }).removeAttr('style');
18410
18411        if( !BigText.DEBUG_MODE ) {
18412          $c.remove();
18413        } else {
18414          $c.css({
18415            'background-color': 'rgba(255,255,255,.4)'
18416          });
18417        }
18418
18419        return {
18420          fontSizes: fontSizes,
18421          wordSpacings: wordSpacings,
18422          ratios: ratios,
18423          minFontSizes: minFontSizes
18424        };
18425      }
18426    };
18427
18428  $.fn.bigtext = BigText.jQueryMethod;
18429  window.BigText = BigText;
18430
18431})(this, jQuery);
vendor: 16,093 bytes, lines 18432-19089
18432/*!
18433 * Isotope PACKAGED v3.0.6
18434 *
18435 * Licensed GPLv3 for open source use
18436 * or Isotope Commercial License for commercial use
18437 *
18438 * https://isotope.metafizzy.co
18439 * Copyright 2010-2018 Metafizzy
18440 */
18441
18442/**
18443 * Bridget makes jQuery widgets
18444 * v2.0.1
18445 * MIT license
18446 */
18447
18448/* jshint browser: true, strict: true, undef: true, unused: true */
18449
18450( function( window, factory ) {
18451  // universal module definition
18452  /*jshint strict: false */ /* globals define, module, require */
18453  if ( typeof define == 'function' && define.amd ) {
18454    // AMD
18455    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
18456      return factory( window, jQuery );
18457    });
18458  } else if ( typeof module == 'object' && module.exports ) {
18459    // CommonJS
18460    module.exports = factory(
18461      window,
18462      require('jquery')
18463    );
18464  } else {
18465    // browser global
18466    window.jQueryBridget = factory(
18467      window,
18468      window.jQuery
18469    );
18470  }
18471
18472}( window, function factory( window, jQuery ) {
18473'use strict';
18474
18475// ----- utils ----- //
18476
18477var arraySlice = Array.prototype.slice;
18478
18479// helper function for logging errors
18480// $.error breaks jQuery chaining
18481var console = window.console;
18482var logError = typeof console == 'undefined' ? function() {} :
18483  function( message ) {
18484    console.error( message );
18485  };
18486
18487// ----- jQueryBridget ----- //
18488
18489function jQueryBridget( namespace, PluginClass, $ ) {
18490  $ = $ || jQuery || window.jQuery;
18491  if ( !$ ) {
18492    return;
18493  }
18494
18495  // add option method -> $().plugin('option', {...})
18496  if ( !PluginClass.prototype.option ) {
18497    // option setter
18498    PluginClass.prototype.option = function( opts ) {
18499      // bail out if not an object
18500      if ( !$.isPlainObject( opts ) ){
18501        return;
18502      }
18503      this.options = $.extend( true, this.options, opts );
18504    };
18505  }
18506
18507  // make jQuery plugin
18508  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
18509    if ( typeof arg0 == 'string' ) {
18510      // method call $().plugin( 'methodName', { options } )
18511      // shift arguments by 1
18512      var args = arraySlice.call( arguments, 1 );
18513      return methodCall( this, arg0, args );
18514    }
18515    // just $().plugin({ options })
18516    plainCall( this, arg0 );
18517    return this;
18518  };
18519
18520  // $().plugin('methodName')
18521  function methodCall( $elems, methodName, args ) {
18522    var returnValue;
18523    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
18524
18525    $elems.each( function( i, elem ) {
18526      // get instance
18527      var instance = $.data( elem, namespace );
18528      if ( !instance ) {
18529        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
18530          pluginMethodStr );
18531        return;
18532      }
18533
18534      var method = instance[ methodName ];
18535      if ( !method || methodName.charAt(0) == '_' ) {
18536        logError( pluginMethodStr + ' is not a valid method' );
18537        return;
18538      }
18539
18540      // apply method, get return value
18541      var value = method.apply( instance, args );
18542      // set return value if value is returned, use only first value
18543      returnValue = returnValue === undefined ? value : returnValue;
18544    });
18545
18546    return returnValue !== undefined ? returnValue : $elems;
18547  }
18548
18549  function plainCall( $elems, options ) {
18550    $elems.each( function( i, elem ) {
18551      var instance = $.data( elem, namespace );
18552      if ( instance ) {
18553        // set options & init
18554        instance.option( options );
18555        instance._init();
18556      } else {
18557        // initialize new instance
18558        instance = new PluginClass( elem, options );
18559        $.data( elem, namespace, instance );
18560      }
18561    });
18562  }
18563
18564  updateJQuery( $ );
18565
18566}
18567
18568// ----- updateJQuery ----- //
18569
18570// set $.bridget for v1 backwards compatibility
18571function updateJQuery( $ ) {
18572  if ( !$ || ( $ && $.bridget ) ) {
18573    return;
18574  }
18575  $.bridget = jQueryBridget;
18576}
18577
18578updateJQuery( jQuery || window.jQuery );
18579
18580// -----  ----- //
18581
18582return jQueryBridget;
18583
18584}));
18585
18586/**
18587 * EvEmitter v1.1.0
18588 * Lil' event emitter
18589 * MIT License
18590 */
18591
18592/* jshint unused: true, undef: true, strict: true */
18593
18594( function( global, factory ) {
18595  // universal module definition
18596  /* jshint strict: false */ /* globals define, module, window */
18597  if ( typeof define == 'function' && define.amd ) {
18598    // AMD - RequireJS
18599    define( 'ev-emitter/ev-emitter',factory );
18600  } else if ( typeof module == 'object' && module.exports ) {
18601    // CommonJS - Browserify, Webpack
18602    module.exports = factory();
18603  } else {
18604    // Browser globals
18605    global.EvEmitter = factory();
18606  }
18607
18608}( typeof window != 'undefined' ? window : this, function() {
18609
18610
18611
18612function EvEmitter() {}
18613
18614var proto = EvEmitter.prototype;
18615
18616proto.on = function( eventName, listener ) {
18617  if ( !eventName || !listener ) {
18618    return;
18619  }
18620  // set events hash
18621  var events = this._events = this._events || {};
18622  // set listeners array
18623  var listeners = events[ eventName ] = events[ eventName ] || [];
18624  // only add once
18625  if ( listeners.indexOf( listener ) == -1 ) {
18626    listeners.push( listener );
18627  }
18628
18629  return this;
18630};
18631
18632proto.once = function( eventName, listener ) {
18633  if ( !eventName || !listener ) {
18634    return;
18635  }
18636  // add event
18637  this.on( eventName, listener );
18638  // set once flag
18639  // set onceEvents hash
18640  var onceEvents = this._onceEvents = this._onceEvents || {};
18641  // set onceListeners object
18642  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
18643  // set flag
18644  onceListeners[ listener ] = true;
18645
18646  return this;
18647};
18648
18649proto.off = function( eventName, listener ) {
18650  var listeners = this._events && this._events[ eventName ];
18651  if ( !listeners || !listeners.length ) {
18652    return;
18653  }
18654  var index = listeners.indexOf( listener );
18655  if ( index != -1 ) {
18656    listeners.splice( index, 1 );
18657  }
18658
18659  return this;
18660};
18661
18662proto.emitEvent = function( eventName, args ) {
18663  var listeners = this._events && this._events[ eventName ];
18664  if ( !listeners || !listeners.length ) {
18665    return;
18666  }
18667  // copy over to avoid interference if .off() in listener
18668  listeners = listeners.slice(0);
18669  args = args || [];
18670  // once stuff
18671  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
18672
18673  for ( var i=0; i < listeners.length; i++ ) {
18674    var listener = listeners[i]
18675    var isOnce = onceListeners && onceListeners[ listener ];
18676    if ( isOnce ) {
18677      // remove listener
18678      // remove before trigger to prevent recursion
18679      this.off( eventName, listener );
18680      // unset once flag
18681      delete onceListeners[ listener ];
18682    }
18683    // trigger listener
18684    listener.apply( this, args );
18685  }
18686
18687  return this;
18688};
18689
18690proto.allOff = function() {
18691  delete this._events;
18692  delete this._onceEvents;
18693};
18694
18695return EvEmitter;
18696
18697}));
18698
18699/*!
18700 * getSize v2.0.3
18701 * measure size of elements
18702 * MIT license
18703 */
18704
18705/* jshint browser: true, strict: true, undef: true, unused: true */
18706/* globals console: false */
18707
18708( function( window, factory ) {
18709  /* jshint strict: false */ /* globals define, module */
18710  if ( typeof define == 'function' && define.amd ) {
18711    // AMD
18712    define( 'get-size/get-size',factory );
18713  } else if ( typeof module == 'object' && module.exports ) {
18714    // CommonJS
18715    module.exports = factory();
18716  } else {
18717    // browser global
18718    window.getSize = factory();
18719  }
18720
18721})( window, function factory() {
18722'use strict';
18723
18724// -------------------------- helpers -------------------------- //
18725
18726// get a number from a string, not a percentage
18727function getStyleSize( value ) {
18728  var num = parseFloat( value );
18729  // not a percent like '100%', and a number
18730  var isValid = value.indexOf('%') == -1 && !isNaN( num );
18731  return isValid && num;
18732}
18733
18734function noop() {}
18735
18736var logError = typeof console == 'undefined' ? noop :
18737  function( message ) {
18738    console.error( message );
18739  };
18740
18741// -------------------------- measurements -------------------------- //
18742
18743var measurements = [
18744  'paddingLeft',
18745  'paddingRight',
18746  'paddingTop',
18747  'paddingBottom',
18748  'marginLeft',
18749  'marginRight',
18750  'marginTop',
18751  'marginBottom',
18752  'borderLeftWidth',
18753  'borderRightWidth',
18754  'borderTopWidth',
18755  'borderBottomWidth'
18756];
18757
18758var measurementsLength = measurements.length;
18759
18760function getZeroSize() {
18761  var size = {
18762    width: 0,
18763    height: 0,
18764    innerWidth: 0,
18765    innerHeight: 0,
18766    outerWidth: 0,
18767    outerHeight: 0
18768  };
18769  for ( var i=0; i < measurementsLength; i++ ) {
18770    var measurement = measurements[i];
18771    size[ measurement ] = 0;
18772  }
18773  return size;
18774}
18775
18776// -------------------------- getStyle -------------------------- //
18777
18778/**
18779 * getStyle, get style of element, check for Firefox bug
18780 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
18781 */
18782function getStyle( elem ) {
18783  var style = getComputedStyle( elem );
18784  if ( !style ) {
18785    logError( 'Style returned ' + style +
18786      '. Are you running this code in a hidden iframe on Firefox? ' +
18787      'See https://bit.ly/getsizebug1' );
18788  }
18789  return style;
18790}
18791
18792// -------------------------- setup -------------------------- //
18793
18794var isSetup = false;
18795
18796var isBoxSizeOuter;
18797
18798/**
18799 * setup
18800 * check isBoxSizerOuter
18801 * do on first getSize() rather than on page load for Firefox bug
18802 */
18803function setup() {
18804  // setup once
18805  if ( isSetup ) {
18806    return;
18807  }
18808  isSetup = true;
18809
18810  // -------------------------- box sizing -------------------------- //
18811
18812  /**
18813   * Chrome & Safari measure the outer-width on style.width on border-box elems
18814   * IE11 & Firefox<29 measures the inner-width
18815   */
18816  var div = document.createElement('div');
18817  div.style.width = '200px';
18818  div.style.padding = '1px 2px 3px 4px';
18819  div.style.borderStyle = 'solid';
18820  div.style.borderWidth = '1px 2px 3px 4px';
18821  div.style.boxSizing = 'border-box';
18822
18823  var body = document.body || document.documentElement;
18824  body.appendChild( div );
18825  var style = getStyle( div );
18826  // round value for browser zoom. desandro/masonry#928
18827  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
18828  getSize.isBoxSizeOuter = isBoxSizeOuter;
18829
18830  body.removeChild( div );
18831}
18832
18833// -------------------------- getSize -------------------------- //
18834
18835function getSize( elem ) {
18836  setup();
18837
18838  // use querySeletor if elem is string
18839  if ( typeof elem == 'string' ) {
18840    elem = document.querySelector( elem );
18841  }
18842
18843  // do not proceed on non-objects
18844  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
18845    return;
18846  }
18847
18848  var style = getStyle( elem );
18849
18850  // if hidden, everything is 0
18851  if ( style.display == 'none' ) {
18852    return getZeroSize();
18853  }
18854
18855  var size = {};
18856  size.width = elem.offsetWidth;
18857  size.height = elem.offsetHeight;
18858
18859  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
18860
18861  // get all measurements
18862  for ( var i=0; i < measurementsLength; i++ ) {
18863    var measurement = measurements[i];
18864    var value = style[ measurement ];
18865    var num = parseFloat( value );
18866    // any 'auto', 'medium' value will be 0
18867    size[ measurement ] = !isNaN( num ) ? num : 0;
18868  }
18869
18870  var paddingWidth = size.paddingLeft + size.paddingRight;
18871  var paddingHeight = size.paddingTop + size.paddingBottom;
18872  var marginWidth = size.marginLeft + size.marginRight;
18873  var marginHeight = size.marginTop + size.marginBottom;
18874  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
18875  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
18876
18877  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
18878
18879  // overwrite width and height if we can get it from style
18880  var styleWidth = getStyleSize( style.width );
18881  if ( styleWidth !== false ) {
18882    size.width = styleWidth +
18883      // add padding and border unless it's already including it
18884      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
18885  }
18886
18887  var styleHeight = getStyleSize( style.height );
18888  if ( styleHeight !== false ) {
18889    size.height = styleHeight +
18890      // add padding and border unless it's already including it
18891      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
18892  }
18893
18894  size.innerWidth = size.width - ( paddingWidth + borderWidth );
18895  size.innerHeight = size.height - ( paddingHeight + borderHeight );
18896
18897  size.outerWidth = size.width + marginWidth;
18898  size.outerHeight = size.height + marginHeight;
18899
18900  return size;
18901}
18902
18903return getSize;
18904
18905});
18906
18907/**
18908 * matchesSelector v2.0.2
18909 * matchesSelector( element, '.selector' )
18910 * MIT license
18911 */
18912
18913/*jshint browser: true, strict: true, undef: true, unused: true */
18914
18915( function( window, factory ) {
18916  /*global define: false, module: false */
18917  'use strict';
18918  // universal module definition
18919  if ( typeof define == 'function' && define.amd ) {
18920    // AMD
18921    define( 'desandro-matches-selector/matches-selector',factory );
18922  } else if ( typeof module == 'object' && module.exports ) {
18923    // CommonJS
18924    module.exports = factory();
18925  } else {
18926    // browser global
18927    window.matchesSelector = factory();
18928  }
18929
18930}( window, function factory() {
18931  'use strict';
18932
18933  var matchesMethod = ( function() {
18934    var ElemProto = window.Element.prototype;
18935    // check for the standard method name first
18936    if ( ElemProto.matches ) {
18937      return 'matches';
18938    }
18939    // check un-prefixed
18940    if ( ElemProto.matchesSelector ) {
18941      return 'matchesSelector';
18942    }
18943    // check vendor prefixes
18944    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
18945
18946    for ( var i=0; i < prefixes.length; i++ ) {
18947      var prefix = prefixes[i];
18948      var method = prefix + 'MatchesSelector';
18949      if ( ElemProto[ method ] ) {
18950        return method;
18951      }
18952    }
18953  })();
18954
18955  return function matchesSelector( elem, selector ) {
18956    return elem[ matchesMethod ]( selector );
18957  };
18958
18959}));
18960
18961/**
18962 * Fizzy UI utils v2.0.7
18963 * MIT license
18964 */
18965
18966/*jshint browser: true, undef: true, unused: true, strict: true */
18967
18968( function( window, factory ) {
18969  // universal module definition
18970  /*jshint strict: false */ /*globals define, module, require */
18971
18972  if ( typeof define == 'function' && define.amd ) {
18973    // AMD
18974    define( 'fizzy-ui-utils/utils',[
18975      'desandro-matches-selector/matches-selector'
18976    ], function( matchesSelector ) {
18977      return factory( window, matchesSelector );
18978    });
18979  } else if ( typeof module == 'object' && module.exports ) {
18980    // CommonJS
18981    module.exports = factory(
18982      window,
18983      require('desandro-matches-selector')
18984    );
18985  } else {
18986    // browser global
18987    window.fizzyUIUtils = factory(
18988      window,
18989      window.matchesSelector
18990    );
18991  }
18992
18993}( window, function factory( window, matchesSelector ) {
18994
18995
18996
18997var utils = {};
18998
18999// ----- extend ----- //
19000
19001// extends objects
19002utils.extend = function( a, b ) {
19003  for ( var prop in b ) {
19004    a[ prop ] = b[ prop ];
19005  }
19006  return a;
19007};
19008
19009// ----- modulo ----- //
19010
19011utils.modulo = function( num, div ) {
19012  return ( ( num % div ) + div ) % div;
19013};
19014
19015// ----- makeArray ----- //
19016
19017var arraySlice = Array.prototype.slice;
19018
19019// turn element or nodeList into an array
19020utils.makeArray = function( obj ) {
19021  if ( Array.isArray( obj ) ) {
19022    // use object if already an array
19023    return obj;
19024  }
19025  // return empty array if undefined or null. #6
19026  if ( obj === null || obj === undefined ) {
19027    return [];
19028  }
19029
19030  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
19031  if ( isArrayLike ) {
19032    // convert nodeList to array
19033    return arraySlice.call( obj );
19034  }
19035
19036  // array of single index
19037  return [ obj ];
19038};
19039
19040// ----- removeFrom ----- //
19041
19042utils.removeFrom = function( ary, obj ) {
19043  var index = ary.indexOf( obj );
19044  if ( index != -1 ) {
19045    ary.splice( index, 1 );
19046  }
19047};
19048
19049// ----- getParent ----- //
19050
19051utils.getParent = function( elem, selector ) {
19052  while ( elem.parentNode && elem != document.body ) {
19053    elem = elem.parentNode;
19054    if ( matchesSelector( elem, selector ) ) {
19055      return elem;
19056    }
19057  }
19058};
19059
19060// ----- getQueryElement ----- //
19061
19062// use element as selector string
19063utils.getQueryElement = function( elem ) {
19064  if ( typeof elem == 'string' ) {
19065    return document.querySelector( elem );
19066  }
19067  return elem;
19068};
19069
19070// ----- handleEvent ----- //
19071
19072// enable .ontype to trigger from .addEventListener( elem, 'type' )
19073utils.handleEvent = function( event ) {
19074  var method = 'on' + event.type;
19075  if ( this[ method ] ) {
19076    this[ method ]( event );
19077  }
19078};
19079
19080// ----- filterFindElements ----- //
19081
19082utils.filterFindElements = function( elems, selector ) {
19083  // make array of elems
19084  elems = utils.makeArray( elems );
19085  var ffElems = [];
19086
19087  elems.forEach( function( elem ) {
19088    // check that elem is an actual element
19089    
19089// START UNCODE EDIT
19090    // if ( !( elem instanceof HTMLElement ) ) {
19091    if ( !( elem instanceof HTMLElement ) && !SiteParameters.is_frontend_editor ) {
19092    // END UNCODE EDIT
vendor: 75,264 bytes, lines 19092-21997
19092
19093      return;
19094    }
19095    // add elem if no selector
19096    if ( !selector ) {
19097      ffElems.push( elem );
19098      return;
19099    }
19100    // filter & find items if we have a selector
19101    // filter
19102    if ( matchesSelector( elem, selector ) ) {
19103      ffElems.push( elem );
19104    }
19105    // find children
19106    var childElems = elem.querySelectorAll( selector );
19107    // concat childElems to filterFound array
19108    for ( var i=0; i < childElems.length; i++ ) {
19109      ffElems.push( childElems[i] );
19110    }
19111  });
19112
19113  return ffElems;
19114};
19115
19116// ----- debounceMethod ----- //
19117
19118utils.debounceMethod = function( _class, methodName, threshold ) {
19119  threshold = threshold || 100;
19120  // original method
19121  var method = _class.prototype[ methodName ];
19122  var timeoutName = methodName + 'Timeout';
19123
19124  _class.prototype[ methodName ] = function() {
19125    var timeout = this[ timeoutName ];
19126    clearTimeout( timeout );
19127
19128    var args = arguments;
19129    var _this = this;
19130    this[ timeoutName ] = setTimeout( function() {
19131      method.apply( _this, args );
19132      delete _this[ timeoutName ];
19133    }, threshold );
19134  };
19135};
19136
19137// ----- docReady ----- //
19138
19139utils.docReady = function( callback ) {
19140  var readyState = document.readyState;
19141  if ( readyState == 'complete' || readyState == 'interactive' ) {
19142    // do async to allow for other scripts to run. metafizzy/flickity#441
19143    setTimeout( callback );
19144  } else {
19145    document.addEventListener( 'DOMContentLoaded', callback );
19146  }
19147};
19148
19149// ----- htmlInit ----- //
19150
19151// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
19152utils.toDashed = function( str ) {
19153  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
19154    return $1 + '-' + $2;
19155  }).toLowerCase();
19156};
19157
19158var console = window.console;
19159/**
19160 * allow user to initialize classes via [data-namespace] or .js-namespace class
19161 * htmlInit( Widget, 'widgetName' )
19162 * options are parsed from data-namespace-options
19163 */
19164utils.htmlInit = function( WidgetClass, namespace ) {
19165  utils.docReady( function() {
19166    var dashedNamespace = utils.toDashed( namespace );
19167    var dataAttr = 'data-' + dashedNamespace;
19168    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
19169    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
19170    var elems = utils.makeArray( dataAttrElems )
19171      .concat( utils.makeArray( jsDashElems ) );
19172    var dataOptionsAttr = dataAttr + '-options';
19173    var jQuery = window.jQuery;
19174
19175    elems.forEach( function( elem ) {
19176      var attr = elem.getAttribute( dataAttr ) ||
19177        elem.getAttribute( dataOptionsAttr );
19178      var options;
19179      try {
19180        options = attr && JSON.parse( attr );
19181      } catch ( error ) {
19182        // log error, do not initialize
19183        if ( console ) {
19184          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
19185          ': ' + error );
19186        }
19187        return;
19188      }
19189      // initialize
19190      var instance = new WidgetClass( elem, options );
19191      // make available via $().data('namespace')
19192      if ( jQuery ) {
19193        jQuery.data( elem, namespace, instance );
19194      }
19195    });
19196
19197  });
19198};
19199
19200// -----  ----- //
19201
19202return utils;
19203
19204}));
19205
19206/**
19207 * Outlayer Item
19208 */
19209
19210( function( window, factory ) {
19211  // universal module definition
19212  /* jshint strict: false */ /* globals define, module, require */
19213  if ( typeof define == 'function' && define.amd ) {
19214    // AMD - RequireJS
19215    define( 'outlayer/item',[
19216        'ev-emitter/ev-emitter',
19217        'get-size/get-size'
19218      ],
19219      factory
19220    );
19221  } else if ( typeof module == 'object' && module.exports ) {
19222    // CommonJS - Browserify, Webpack
19223    module.exports = factory(
19224      require('ev-emitter'),
19225      require('get-size')
19226    );
19227  } else {
19228    // browser global
19229    window.Outlayer = {};
19230    window.Outlayer.Item = factory(
19231      window.EvEmitter,
19232      window.getSize
19233    );
19234  }
19235
19236}( window, function factory( EvEmitter, getSize ) {
19237'use strict';
19238
19239// ----- helpers ----- //
19240
19241function isEmptyObj( obj ) {
19242  for ( var prop in obj ) {
19243    return false;
19244  }
19245  prop = null;
19246  return true;
19247}
19248
19249// -------------------------- CSS3 support -------------------------- //
19250
19251
19252var docElemStyle = document.documentElement.style;
19253
19254var transitionProperty = typeof docElemStyle.transition == 'string' ?
19255  'transition' : 'WebkitTransition';
19256var transformProperty = typeof docElemStyle.transform == 'string' ?
19257  'transform' : 'WebkitTransform';
19258
19259var transitionEndEvent = {
19260  WebkitTransition: 'webkitTransitionEnd',
19261  transition: 'transitionend'
19262}[ transitionProperty ];
19263
19264// cache all vendor properties that could have vendor prefix
19265var vendorProperties = {
19266  transform: transformProperty,
19267  transition: transitionProperty,
19268  transitionDuration: transitionProperty + 'Duration',
19269  transitionProperty: transitionProperty + 'Property',
19270  transitionDelay: transitionProperty + 'Delay'
19271};
19272
19273// -------------------------- Item -------------------------- //
19274
19275function Item( element, layout ) {
19276  if ( !element ) {
19277    return;
19278  }
19279
19280  this.element = element;
19281  // parent layout class, i.e. Masonry, Isotope, or Packery
19282  this.layout = layout;
19283  this.position = {
19284    x: 0,
19285    y: 0
19286  };
19287
19288  this._create();
19289}
19290
19291// inherit EvEmitter
19292var proto = Item.prototype = Object.create( EvEmitter.prototype );
19293proto.constructor = Item;
19294
19295proto._create = function() {
19296  // transition objects
19297  this._transn = {
19298    ingProperties: {},
19299    clean: {},
19300    onEnd: {}
19301  };
19302
19303  this.css({
19304    position: 'absolute'
19305  });
19306};
19307
19308// trigger specified handler for event type
19309proto.handleEvent = function( event ) {
19310  var method = 'on' + event.type;
19311  if ( this[ method ] ) {
19312    this[ method ]( event );
19313  }
19314};
19315
19316proto.getSize = function() {
19317  this.size = getSize( this.element );
19318};
19319
19320/**
19321 * apply CSS styles to element
19322 * @param {Object} style
19323 */
19324proto.css = function( style ) {
19325  var elemStyle = this.element.style;
19326
19327  for ( var prop in style ) {
19328    // use vendor property if available
19329    var supportedProp = vendorProperties[ prop ] || prop;
19330    elemStyle[ supportedProp ] = style[ prop ];
19331  }
19332};
19333
19334 // measure position, and sets it
19335proto.getPosition = function() {
19336  var style = getComputedStyle( this.element );
19337  var isOriginLeft = this.layout._getOption('originLeft');
19338  var isOriginTop = this.layout._getOption('originTop');
19339  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
19340  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
19341  var x = parseFloat( xValue );
19342  var y = parseFloat( yValue );
19343  // convert percent to pixels
19344  var layoutSize = this.layout.size;
19345  if ( xValue.indexOf('%') != -1 ) {
19346    x = ( x / 100 ) * layoutSize.width;
19347  }
19348  if ( yValue.indexOf('%') != -1 ) {
19349    y = ( y / 100 ) * layoutSize.height;
19350  }
19351  // clean up 'auto' or other non-integer values
19352  x = isNaN( x ) ? 0 : x;
19353  y = isNaN( y ) ? 0 : y;
19354  // remove padding from measurement
19355  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
19356  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
19357
19358  this.position.x = x;
19359  this.position.y = y;
19360};
19361
19362// set settled position, apply padding
19363proto.layoutPosition = function() {
19364  var layoutSize = this.layout.size;
19365  var style = {};
19366  var isOriginLeft = this.layout._getOption('originLeft');
19367  var isOriginTop = this.layout._getOption('originTop');
19368
19369  // x
19370  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
19371  var xProperty = isOriginLeft ? 'left' : 'right';
19372  var xResetProperty = isOriginLeft ? 'right' : 'left';
19373
19374  var x = this.position.x + layoutSize[ xPadding ];
19375  // set in percentage or pixels
19376  style[ xProperty ] = this.getXValue( x );
19377  // reset other property
19378  style[ xResetProperty ] = '';
19379
19380  // y
19381  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
19382  var yProperty = isOriginTop ? 'top' : 'bottom';
19383  var yResetProperty = isOriginTop ? 'bottom' : 'top';
19384
19385  var y = this.position.y + layoutSize[ yPadding ];
19386  // set in percentage or pixels
19387  style[ yProperty ] = this.getYValue( y );
19388  // reset other property
19389  style[ yResetProperty ] = '';
19390
19391  this.css( style );
19392  this.emitEvent( 'layout', [ this ] );
19393};
19394
19395proto.getXValue = function( x ) {
19396  var isHorizontal = this.layout._getOption('horizontal');
19397  return this.layout.options.percentPosition && !isHorizontal ?
19398    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
19399};
19400
19401proto.getYValue = function( y ) {
19402  var isHorizontal = this.layout._getOption('horizontal');
19403  return this.layout.options.percentPosition && isHorizontal ?
19404    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
19405};
19406
19407proto._transitionTo = function( x, y ) {
19408  this.getPosition();
19409  // get current x & y from top/left
19410  var curX = this.position.x;
19411  var curY = this.position.y;
19412
19413  var didNotMove = x == this.position.x && y == this.position.y;
19414
19415  // save end position
19416  this.setPosition( x, y );
19417
19418  // if did not move and not transitioning, just go to layout
19419  if ( didNotMove && !this.isTransitioning ) {
19420    this.layoutPosition();
19421    return;
19422  }
19423
19424  var transX = x - curX;
19425  var transY = y - curY;
19426  var transitionStyle = {};
19427  transitionStyle.transform = this.getTranslate( transX, transY );
19428
19429  this.transition({
19430    to: transitionStyle,
19431    onTransitionEnd: {
19432      transform: this.layoutPosition
19433    },
19434    isCleaning: true
19435  });
19436};
19437
19438proto.getTranslate = function( x, y ) {
19439  // flip cooridinates if origin on right or bottom
19440  var isOriginLeft = this.layout._getOption('originLeft');
19441  var isOriginTop = this.layout._getOption('originTop');
19442  x = isOriginLeft ? x : -x;
19443  y = isOriginTop ? y : -y;
19444  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
19445};
19446
19447// non transition + transform support
19448proto.goTo = function( x, y ) {
19449  this.setPosition( x, y );
19450  this.layoutPosition();
19451};
19452
19453proto.moveTo = proto._transitionTo;
19454
19455proto.setPosition = function( x, y ) {
19456  this.position.x = parseFloat( x );
19457  this.position.y = parseFloat( y );
19458};
19459
19460// ----- transition ----- //
19461
19462/**
19463 * @param {Object} style - CSS
19464 * @param {Function} onTransitionEnd
19465 */
19466
19467// non transition, just trigger callback
19468proto._nonTransition = function( args ) {
19469  this.css( args.to );
19470  if ( args.isCleaning ) {
19471    this._removeStyles( args.to );
19472  }
19473  for ( var prop in args.onTransitionEnd ) {
19474    args.onTransitionEnd[ prop ].call( this );
19475  }
19476};
19477
19478/**
19479 * proper transition
19480 * @param {Object} args - arguments
19481 *   @param {Object} to - style to transition to
19482 *   @param {Object} from - style to start transition from
19483 *   @param {Boolean} isCleaning - removes transition styles after transition
19484 *   @param {Function} onTransitionEnd - callback
19485 */
19486proto.transition = function( args ) {
19487  // redirect to nonTransition if no transition duration
19488  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
19489    this._nonTransition( args );
19490    return;
19491  }
19492
19493  var _transition = this._transn;
19494  // keep track of onTransitionEnd callback by css property
19495  for ( var prop in args.onTransitionEnd ) {
19496    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
19497  }
19498  // keep track of properties that are transitioning
19499  for ( prop in args.to ) {
19500    _transition.ingProperties[ prop ] = true;
19501    // keep track of properties to clean up when transition is done
19502    if ( args.isCleaning ) {
19503      _transition.clean[ prop ] = true;
19504    }
19505  }
19506
19507  // set from styles
19508  if ( args.from ) {
19509    this.css( args.from );
19510    // force redraw. http://blog.alexmaccaw.com/css-transitions
19511    var h = this.element.offsetHeight;
19512    // hack for JSHint to hush about unused var
19513    h = null;
19514  }
19515  // enable transition
19516  this.enableTransition( args.to );
19517  // set styles that are transitioning
19518  this.css( args.to );
19519
19520  this.isTransitioning = true;
19521
19522};
19523
19524// dash before all cap letters, including first for
19525// WebkitTransform => -webkit-transform
19526function toDashedAll( str ) {
19527  return str.replace( /([A-Z])/g, function( $1 ) {
19528    return '-' + $1.toLowerCase();
19529  });
19530}
19531
19532var transitionProps = 'opacity,' + toDashedAll( transformProperty );
19533
19534proto.enableTransition = function(/* style */) {
19535  // HACK changing transitionProperty during a transition
19536  // will cause transition to jump
19537  if ( this.isTransitioning ) {
19538    return;
19539  }
19540
19541  // make `transition: foo, bar, baz` from style object
19542  // HACK un-comment this when enableTransition can work
19543  // while a transition is happening
19544  // var transitionValues = [];
19545  // for ( var prop in style ) {
19546  //   // dash-ify camelCased properties like WebkitTransition
19547  //   prop = vendorProperties[ prop ] || prop;
19548  //   transitionValues.push( toDashedAll( prop ) );
19549  // }
19550  // munge number to millisecond, to match stagger
19551  var duration = this.layout.options.transitionDuration;
19552  duration = typeof duration == 'number' ? duration + 'ms' : duration;
19553  // enable transition styles
19554  this.css({
19555    transitionProperty: transitionProps,
19556    transitionDuration: duration,
19557    transitionDelay: this.staggerDelay || 0
19558  });
19559  // listen for transition end event
19560  this.element.addEventListener( transitionEndEvent, this, false );
19561};
19562
19563// ----- events ----- //
19564
19565proto.onwebkitTransitionEnd = function( event ) {
19566  this.ontransitionend( event );
19567};
19568
19569proto.onotransitionend = function( event ) {
19570  this.ontransitionend( event );
19571};
19572
19573// properties that I munge to make my life easier
19574var dashedVendorProperties = {
19575  '-webkit-transform': 'transform'
19576};
19577
19578proto.ontransitionend = function( event ) {
19579  // disregard bubbled events from children
19580  if ( event.target !== this.element ) {
19581    return;
19582  }
19583  var _transition = this._transn;
19584  // get property name of transitioned property, convert to prefix-free
19585  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
19586
19587  // remove property that has completed transitioning
19588  delete _transition.ingProperties[ propertyName ];
19589  // check if any properties are still transitioning
19590  if ( isEmptyObj( _transition.ingProperties ) ) {
19591    // all properties have completed transitioning
19592    this.disableTransition();
19593  }
19594  // clean style
19595  if ( propertyName in _transition.clean ) {
19596    // clean up style
19597    this.element.style[ event.propertyName ] = '';
19598    delete _transition.clean[ propertyName ];
19599  }
19600  // trigger onTransitionEnd callback
19601  if ( propertyName in _transition.onEnd ) {
19602    var onTransitionEnd = _transition.onEnd[ propertyName ];
19603    onTransitionEnd.call( this );
19604    delete _transition.onEnd[ propertyName ];
19605  }
19606
19607  this.emitEvent( 'transitionEnd', [ this ] );
19608};
19609
19610proto.disableTransition = function() {
19611  this.removeTransitionStyles();
19612  this.element.removeEventListener( transitionEndEvent, this, false );
19613  this.isTransitioning = false;
19614};
19615
19616/**
19617 * removes style property from element
19618 * @param {Object} style
19619**/
19620proto._removeStyles = function( style ) {
19621  // clean up transition styles
19622  var cleanStyle = {};
19623  for ( var prop in style ) {
19624    cleanStyle[ prop ] = '';
19625  }
19626  this.css( cleanStyle );
19627};
19628
19629var cleanTransitionStyle = {
19630  transitionProperty: '',
19631  transitionDuration: '',
19632  transitionDelay: ''
19633};
19634
19635proto.removeTransitionStyles = function() {
19636  // remove transition
19637  this.css( cleanTransitionStyle );
19638};
19639
19640// ----- stagger ----- //
19641
19642proto.stagger = function( delay ) {
19643  delay = isNaN( delay ) ? 0 : delay;
19644  this.staggerDelay = delay + 'ms';
19645};
19646
19647// ----- show/hide/remove ----- //
19648
19649// remove element from DOM
19650proto.removeElem = function() {
19651  this.element.parentNode.removeChild( this.element );
19652  // remove display: none
19653  this.css({ display: '' });
19654  this.emitEvent( 'remove', [ this ] );
19655};
19656
19657proto.remove = function() {
19658  // just remove element if no transition support or no transition
19659  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
19660    this.removeElem();
19661    return;
19662  }
19663
19664  // start transition
19665  this.once( 'transitionEnd', function() {
19666    this.removeElem();
19667  });
19668  this.hide();
19669};
19670
19671proto.reveal = function() {
19672  delete this.isHidden;
19673  // remove display: none
19674  this.css({ display: '' });
19675
19676  var options = this.layout.options;
19677
19678  var onTransitionEnd = {};
19679  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
19680  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
19681
19682  this.transition({
19683    from: options.hiddenStyle,
19684    to: options.visibleStyle,
19685    isCleaning: true,
19686    onTransitionEnd: onTransitionEnd
19687  });
19688};
19689
19690proto.onRevealTransitionEnd = function() {
19691  // check if still visible
19692  // during transition, item may have been hidden
19693  if ( !this.isHidden ) {
19694    this.emitEvent('reveal');
19695  }
19696};
19697
19698/**
19699 * get style property use for hide/reveal transition end
19700 * @param {String} styleProperty - hiddenStyle/visibleStyle
19701 * @returns {String}
19702 */
19703proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
19704  var optionStyle = this.layout.options[ styleProperty ];
19705  // use opacity
19706  if ( optionStyle.opacity ) {
19707    return 'opacity';
19708  }
19709  // get first property
19710  for ( var prop in optionStyle ) {
19711    return prop;
19712  }
19713};
19714
19715proto.hide = function() {
19716  // set flag
19717  this.isHidden = true;
19718  // remove display: none
19719  this.css({ display: '' });
19720
19721  var options = this.layout.options;
19722
19723  var onTransitionEnd = {};
19724  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
19725  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
19726
19727  this.transition({
19728    from: options.visibleStyle,
19729    to: options.hiddenStyle,
19730    // keep hidden stuff hidden
19731    isCleaning: true,
19732    onTransitionEnd: onTransitionEnd
19733  });
19734};
19735
19736proto.onHideTransitionEnd = function() {
19737  // check if still hidden
19738  // during transition, item may have been un-hidden
19739  if ( this.isHidden ) {
19740    this.css({ display: 'none' });
19741    this.emitEvent('hide');
19742  }
19743};
19744
19745proto.destroy = function() {
19746  this.css({
19747    position: '',
19748    left: '',
19749    right: '',
19750    top: '',
19751    bottom: '',
19752    transition: '',
19753    transform: ''
19754  });
19755};
19756
19757return Item;
19758
19759}));
19760
19761/*!
19762 * Outlayer v2.1.1
19763 * the brains and guts of a layout library
19764 * MIT license
19765 */
19766
19767( function( window, factory ) {
19768  'use strict';
19769  // universal module definition
19770  /* jshint strict: false */ /* globals define, module, require */
19771  if ( typeof define == 'function' && define.amd ) {
19772    // AMD - RequireJS
19773    define( 'outlayer/outlayer',[
19774        'ev-emitter/ev-emitter',
19775        'get-size/get-size',
19776        'fizzy-ui-utils/utils',
19777        './item'
19778      ],
19779      function( EvEmitter, getSize, utils, Item ) {
19780        return factory( window, EvEmitter, getSize, utils, Item);
19781      }
19782    );
19783  } else if ( typeof module == 'object' && module.exports ) {
19784    // CommonJS - Browserify, Webpack
19785    module.exports = factory(
19786      window,
19787      require('ev-emitter'),
19788      require('get-size'),
19789      require('fizzy-ui-utils'),
19790      require('./item')
19791    );
19792  } else {
19793    // browser global
19794    window.Outlayer = factory(
19795      window,
19796      window.EvEmitter,
19797      window.getSize,
19798      window.fizzyUIUtils,
19799      window.Outlayer.Item
19800    );
19801  }
19802
19803}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
19804'use strict';
19805
19806// ----- vars ----- //
19807
19808var console = window.console;
19809var jQuery = window.jQuery;
19810var noop = function() {};
19811
19812// -------------------------- Outlayer -------------------------- //
19813
19814// globally unique identifiers
19815var GUID = 0;
19816// internal store of all Outlayer intances
19817var instances = {};
19818
19819
19820/**
19821 * @param {Element, String} element
19822 * @param {Object} options
19823 * @constructor
19824 */
19825function Outlayer( element, options ) {
19826  var queryElement = utils.getQueryElement( element );
19827  if ( !queryElement ) {
19828    if ( console ) {
19829      console.error( 'Bad element for ' + this.constructor.namespace +
19830        ': ' + ( queryElement || element ) );
19831    }
19832    return;
19833  }
19834  this.element = queryElement;
19835  // add jQuery
19836  if ( jQuery ) {
19837    this.$element = jQuery( this.element );
19838  }
19839
19840  // options
19841  this.options = utils.extend( {}, this.constructor.defaults );
19842  this.option( options );
19843
19844  // add id for Outlayer.getFromElement
19845  var id = ++GUID;
19846  this.element.outlayerGUID = id; // expando
19847  instances[ id ] = this; // associate via id
19848
19849  // kick it off
19850  this._create();
19851
19852  var isInitLayout = this._getOption('initLayout');
19853  if ( isInitLayout ) {
19854    this.layout();
19855  }
19856}
19857
19858// settings are for internal use only
19859Outlayer.namespace = 'outlayer';
19860Outlayer.Item = Item;
19861
19862// default options
19863Outlayer.defaults = {
19864  containerStyle: {
19865    position: 'relative'
19866  },
19867  initLayout: true,
19868  originLeft: true,
19869  originTop: true,
19870  resize: true,
19871  resizeContainer: true,
19872  // item options
19873  transitionDuration: '0.4s',
19874  hiddenStyle: {
19875    opacity: 0,
19876    transform: 'scale(0.001)'
19877  },
19878  visibleStyle: {
19879    opacity: 1,
19880    transform: 'scale(1)'
19881  }
19882};
19883
19884var proto = Outlayer.prototype;
19885// inherit EvEmitter
19886utils.extend( proto, EvEmitter.prototype );
19887
19888/**
19889 * set options
19890 * @param {Object} opts
19891 */
19892proto.option = function( opts ) {
19893  utils.extend( this.options, opts );
19894};
19895
19896/**
19897 * get backwards compatible option value, check old name
19898 */
19899proto._getOption = function( option ) {
19900  var oldOption = this.constructor.compatOptions[ option ];
19901  return oldOption && this.options[ oldOption ] !== undefined ?
19902    this.options[ oldOption ] : this.options[ option ];
19903};
19904
19905Outlayer.compatOptions = {
19906  // currentName: oldName
19907  initLayout: 'isInitLayout',
19908  horizontal: 'isHorizontal',
19909  layoutInstant: 'isLayoutInstant',
19910  originLeft: 'isOriginLeft',
19911  originTop: 'isOriginTop',
19912  resize: 'isResizeBound',
19913  resizeContainer: 'isResizingContainer'
19914};
19915
19916proto._create = function() {
19917  // get items from children
19918  this.reloadItems();
19919  // elements that affect layout, but are not laid out
19920  this.stamps = [];
19921  this.stamp( this.options.stamp );
19922  // set container style
19923  utils.extend( this.element.style, this.options.containerStyle );
19924
19925  // bind resize method
19926  var canBindResize = this._getOption('resize');
19927  if ( canBindResize ) {
19928    this.bindResize();
19929  }
19930};
19931
19932// goes through all children again and gets bricks in proper order
19933proto.reloadItems = function() {
19934  // collection of item elements
19935  this.items = this._itemize( this.element.children );
19936};
19937
19938
19939/**
19940 * turn elements into Outlayer.Items to be used in layout
19941 * @param {Array or NodeList or HTMLElement} elems
19942 * @returns {Array} items - collection of new Outlayer Items
19943 */
19944proto._itemize = function( elems ) {
19945
19946  var itemElems = this._filterFindItemElements( elems );
19947  var Item = this.constructor.Item;
19948
19949  // create new Outlayer Items for collection
19950  var items = [];
19951  for ( var i=0; i < itemElems.length; i++ ) {
19952    var elem = itemElems[i];
19953    var item = new Item( elem, this );
19954    items.push( item );
19955  }
19956
19957  return items;
19958};
19959
19960/**
19961 * get item elements to be used in layout
19962 * @param {Array or NodeList or HTMLElement} elems
19963 * @returns {Array} items - item elements
19964 */
19965proto._filterFindItemElements = function( elems ) {
19966  return utils.filterFindElements( elems, this.options.itemSelector );
19967};
19968
19969/**
19970 * getter method for getting item elements
19971 * @returns {Array} elems - collection of item elements
19972 */
19973proto.getItemElements = function() {
19974  return this.items.map( function( item ) {
19975    return item.element;
19976  });
19977};
19978
19979// ----- init & layout ----- //
19980
19981/**
19982 * lays out all items
19983 */
19984proto.layout = function() {
19985  this._resetLayout();
19986  this._manageStamps();
19987
19988  // don't animate first layout
19989  var layoutInstant = this._getOption('layoutInstant');
19990  var isInstant = layoutInstant !== undefined ?
19991    layoutInstant : !this._isLayoutInited;
19992  this.layoutItems( this.items, isInstant );
19993
19994  // flag for initalized
19995  this._isLayoutInited = true;
19996};
19997
19998// _init is alias for layout
19999proto._init = proto.layout;
20000
20001/**
20002 * logic before any new layout
20003 */
20004proto._resetLayout = function() {
20005  this.getSize();
20006};
20007
20008
20009proto.getSize = function() {
20010  this.size = getSize( this.element );
20011};
20012
20013/**
20014 * get measurement from option, for columnWidth, rowHeight, gutter
20015 * if option is String -> get element from selector string, & get size of element
20016 * if option is Element -> get size of element
20017 * else use option as a number
20018 *
20019 * @param {String} measurement
20020 * @param {String} size - width or height
20021 * @private
20022 */
20023proto._getMeasurement = function( measurement, size ) {
20024  var option = this.options[ measurement ];
20025  var elem;
20026  if ( !option ) {
20027    // default to 0
20028    this[ measurement ] = 0;
20029  } else {
20030    // use option as an element
20031    if ( typeof option == 'string' ) {
20032      elem = this.element.querySelector( option );
20033    } else if ( option instanceof HTMLElement ) {
20034      elem = option;
20035    }
20036    // use size of element, if element
20037    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
20038  }
20039};
20040
20041/**
20042 * layout a collection of item elements
20043 * @api public
20044 */
20045proto.layoutItems = function( items, isInstant ) {
20046  items = this._getItemsForLayout( items );
20047
20048  this._layoutItems( items, isInstant );
20049
20050  this._postLayout();
20051};
20052
20053/**
20054 * get the items to be laid out
20055 * you may want to skip over some items
20056 * @param {Array} items
20057 * @returns {Array} items
20058 */
20059proto._getItemsForLayout = function( items ) {
20060  return items.filter( function( item ) {
20061    return !item.isIgnored;
20062  });
20063};
20064
20065/**
20066 * layout items
20067 * @param {Array} items
20068 * @param {Boolean} isInstant
20069 */
20070proto._layoutItems = function( items, isInstant ) {
20071  this._emitCompleteOnItems( 'layout', items );
20072
20073  if ( !items || !items.length ) {
20074    // no items, emit event with empty array
20075    return;
20076  }
20077
20078  var queue = [];
20079
20080  items.forEach( function( item ) {
20081    // get x/y object from method
20082    var position = this._getItemLayoutPosition( item );
20083    // enqueue
20084    position.item = item;
20085    position.isInstant = isInstant || item.isLayoutInstant;
20086    queue.push( position );
20087  }, this );
20088
20089  this._processLayoutQueue( queue );
20090};
20091
20092/**
20093 * get item layout position
20094 * @param {Outlayer.Item} item
20095 * @returns {Object} x and y position
20096 */
20097proto._getItemLayoutPosition = function( /* item */ ) {
20098  return {
20099    x: 0,
20100    y: 0
20101  };
20102};
20103
20104/**
20105 * iterate over array and position each item
20106 * Reason being - separating this logic prevents 'layout invalidation'
20107 * thx @paul_irish
20108 * @param {Array} queue
20109 */
20110proto._processLayoutQueue = function( queue ) {
20111  this.updateStagger();
20112  queue.forEach( function( obj, i ) {
20113    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
20114  }, this );
20115};
20116
20117// set stagger from option in milliseconds number
20118proto.updateStagger = function() {
20119  var stagger = this.options.stagger;
20120  if ( stagger === null || stagger === undefined ) {
20121    this.stagger = 0;
20122    return;
20123  }
20124  this.stagger = getMilliseconds( stagger );
20125  return this.stagger;
20126};
20127
20128/**
20129 * Sets position of item in DOM
20130 * @param {Outlayer.Item} item
20131 * @param {Number} x - horizontal position
20132 * @param {Number} y - vertical position
20133 * @param {Boolean} isInstant - disables transitions
20134 */
20135proto._positionItem = function( item, x, y, isInstant, i ) {
20136  if ( isInstant ) {
20137    // if not transition, just set CSS
20138    item.goTo( x, y );
20139  } else {
20140    item.stagger( i * this.stagger );
20141    item.moveTo( x, y );
20142  }
20143};
20144
20145/**
20146 * Any logic you want to do after each layout,
20147 * i.e. size the container
20148 */
20149proto._postLayout = function() {
20150  this.resizeContainer();
20151};
20152
20153proto.resizeContainer = function() {
20154  var isResizingContainer = this._getOption('resizeContainer');
20155  if ( !isResizingContainer ) {
20156    return;
20157  }
20158  var size = this._getContainerSize();
20159  if ( size ) {
20160    this._setContainerMeasure( size.width, true );
20161    this._setContainerMeasure( size.height, false );
20162  }
20163};
20164
20165/**
20166 * Sets width or height of container if returned
20167 * @returns {Object} size
20168 *   @param {Number} width
20169 *   @param {Number} height
20170 */
20171proto._getContainerSize = noop;
20172
20173/**
20174 * @param {Number} measure - size of width or height
20175 * @param {Boolean} isWidth
20176 */
20177proto._setContainerMeasure = function( measure, isWidth ) {
20178  if ( measure === undefined ) {
20179    return;
20180  }
20181
20182  var elemSize = this.size;
20183  // add padding and border width if border box
20184  if ( elemSize.isBorderBox ) {
20185    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
20186      elemSize.borderLeftWidth + elemSize.borderRightWidth :
20187      elemSize.paddingBottom + elemSize.paddingTop +
20188      elemSize.borderTopWidth + elemSize.borderBottomWidth;
20189  }
20190
20191  measure = Math.max( measure, 0 );
20192  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
20193};
20194
20195/**
20196 * emit eventComplete on a collection of items events
20197 * @param {String} eventName
20198 * @param {Array} items - Outlayer.Items
20199 */
20200proto._emitCompleteOnItems = function( eventName, items ) {
20201  var _this = this;
20202  function onComplete() {
20203    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
20204  }
20205
20206  var count = items.length;
20207  if ( !items || !count ) {
20208    onComplete();
20209    return;
20210  }
20211
20212  var doneCount = 0;
20213  function tick() {
20214    doneCount++;
20215    if ( doneCount == count ) {
20216      onComplete();
20217    }
20218  }
20219
20220  // bind callback
20221  items.forEach( function( item ) {
20222    item.once( eventName, tick );
20223  });
20224};
20225
20226/**
20227 * emits events via EvEmitter and jQuery events
20228 * @param {String} type - name of event
20229 * @param {Event} event - original event
20230 * @param {Array} args - extra arguments
20231 */
20232proto.dispatchEvent = function( type, event, args ) {
20233  // add original event to arguments
20234  var emitArgs = event ? [ event ].concat( args ) : args;
20235  this.emitEvent( type, emitArgs );
20236
20237  if ( jQuery ) {
20238    // set this.$element
20239    this.$element = this.$element || jQuery( this.element );
20240    if ( event ) {
20241      // create jQuery event
20242      var $event = jQuery.Event( event );
20243      $event.type = type;
20244      this.$element.trigger( $event, args );
20245    } else {
20246      // just trigger with type if no event available
20247      this.$element.trigger( type, args );
20248    }
20249  }
20250};
20251
20252// -------------------------- ignore & stamps -------------------------- //
20253
20254
20255/**
20256 * keep item in collection, but do not lay it out
20257 * ignored items do not get skipped in layout
20258 * @param {Element} elem
20259 */
20260proto.ignore = function( elem ) {
20261  var item = this.getItem( elem );
20262  if ( item ) {
20263    item.isIgnored = true;
20264  }
20265};
20266
20267/**
20268 * return item to layout collection
20269 * @param {Element} elem
20270 */
20271proto.unignore = function( elem ) {
20272  var item = this.getItem( elem );
20273  if ( item ) {
20274    delete item.isIgnored;
20275  }
20276};
20277
20278/**
20279 * adds elements to stamps
20280 * @param {NodeList, Array, Element, or String} elems
20281 */
20282proto.stamp = function( elems ) {
20283  elems = this._find( elems );
20284  if ( !elems ) {
20285    return;
20286  }
20287
20288  this.stamps = this.stamps.concat( elems );
20289  // ignore
20290  elems.forEach( this.ignore, this );
20291};
20292
20293/**
20294 * removes elements to stamps
20295 * @param {NodeList, Array, or Element} elems
20296 */
20297proto.unstamp = function( elems ) {
20298  elems = this._find( elems );
20299  if ( !elems ){
20300    return;
20301  }
20302
20303  elems.forEach( function( elem ) {
20304    // filter out removed stamp elements
20305    utils.removeFrom( this.stamps, elem );
20306    this.unignore( elem );
20307  }, this );
20308};
20309
20310/**
20311 * finds child elements
20312 * @param {NodeList, Array, Element, or String} elems
20313 * @returns {Array} elems
20314 */
20315proto._find = function( elems ) {
20316  if ( !elems ) {
20317    return;
20318  }
20319  // if string, use argument as selector string
20320  if ( typeof elems == 'string' ) {
20321    elems = this.element.querySelectorAll( elems );
20322  }
20323  elems = utils.makeArray( elems );
20324  return elems;
20325};
20326
20327proto._manageStamps = function() {
20328  if ( !this.stamps || !this.stamps.length ) {
20329    return;
20330  }
20331
20332  this._getBoundingRect();
20333
20334  this.stamps.forEach( this._manageStamp, this );
20335};
20336
20337// update boundingLeft / Top
20338proto._getBoundingRect = function() {
20339  // get bounding rect for container element
20340  var boundingRect = this.element.getBoundingClientRect();
20341  var size = this.size;
20342  this._boundingRect = {
20343    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
20344    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
20345    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
20346    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
20347  };
20348};
20349
20350/**
20351 * @param {Element} stamp
20352**/
20353proto._manageStamp = noop;
20354
20355/**
20356 * get x/y position of element relative to container element
20357 * @param {Element} elem
20358 * @returns {Object} offset - has left, top, right, bottom
20359 */
20360proto._getElementOffset = function( elem ) {
20361  var boundingRect = elem.getBoundingClientRect();
20362  var thisRect = this._boundingRect;
20363  var size = getSize( elem );
20364  var offset = {
20365    left: boundingRect.left - thisRect.left - size.marginLeft,
20366    top: boundingRect.top - thisRect.top - size.marginTop,
20367    right: thisRect.right - boundingRect.right - size.marginRight,
20368    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
20369  };
20370  return offset;
20371};
20372
20373// -------------------------- resize -------------------------- //
20374
20375// enable event handlers for listeners
20376// i.e. resize -> onresize
20377proto.handleEvent = utils.handleEvent;
20378
20379/**
20380 * Bind layout to window resizing
20381 */
20382proto.bindResize = function() {
20383  window.addEventListener( 'resize', this );
20384  this.isResizeBound = true;
20385};
20386
20387/**
20388 * Unbind layout to window resizing
20389 */
20390proto.unbindResize = function() {
20391  window.removeEventListener( 'resize', this );
20392  this.isResizeBound = false;
20393};
20394
20395proto.onresize = function() {
20396  this.resize();
20397};
20398
20399utils.debounceMethod( Outlayer, 'onresize', 100 );
20400
20401proto.resize = function() {
20402  // don't trigger if size did not change
20403  // or if resize was unbound. See #9
20404  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
20405    return;
20406  }
20407
20408  this.layout();
20409};
20410
20411/**
20412 * check if layout is needed post layout
20413 * @returns Boolean
20414 */
20415proto.needsResizeLayout = function() {
20416  var size = getSize( this.element );
20417  // check that this.size and size are there
20418  // IE8 triggers resize on body size change, so they might not be
20419  var hasSizes = this.size && size;
20420  return hasSizes && size.innerWidth !== this.size.innerWidth;
20421};
20422
20423// -------------------------- methods -------------------------- //
20424
20425/**
20426 * add items to Outlayer instance
20427 * @param {Array or NodeList or Element} elems
20428 * @returns {Array} items - Outlayer.Items
20429**/
20430proto.addItems = function( elems ) {
20431  var items = this._itemize( elems );
20432  // add items to collection
20433  if ( items.length ) {
20434    this.items = this.items.concat( items );
20435  }
20436  return items;
20437};
20438
20439/**
20440 * Layout newly-appended item elements
20441 * @param {Array or NodeList or Element} elems
20442 */
20443proto.appended = function( elems ) {
20444  var items = this.addItems( elems );
20445  if ( !items.length ) {
20446    return;
20447  }
20448  // layout and reveal just the new items
20449  this.layoutItems( items, true );
20450  this.reveal( items );
20451};
20452
20453/**
20454 * Layout prepended elements
20455 * @param {Array or NodeList or Element} elems
20456 */
20457proto.prepended = function( elems ) {
20458  var items = this._itemize( elems );
20459  if ( !items.length ) {
20460    return;
20461  }
20462  // add items to beginning of collection
20463  var previousItems = this.items.slice(0);
20464  this.items = items.concat( previousItems );
20465  // start new layout
20466  this._resetLayout();
20467  this._manageStamps();
20468  // layout new stuff without transition
20469  this.layoutItems( items, true );
20470  this.reveal( items );
20471  // layout previous items
20472  this.layoutItems( previousItems );
20473};
20474
20475/**
20476 * reveal a collection of items
20477 * @param {Array of Outlayer.Items} items
20478 */
20479proto.reveal = function( items ) {
20480  this._emitCompleteOnItems( 'reveal', items );
20481  if ( !items || !items.length ) {
20482    return;
20483  }
20484  var stagger = this.updateStagger();
20485  items.forEach( function( item, i ) {
20486    item.stagger( i * stagger );
20487    item.reveal();
20488  });
20489};
20490
20491/**
20492 * hide a collection of items
20493 * @param {Array of Outlayer.Items} items
20494 */
20495proto.hide = function( items ) {
20496  this._emitCompleteOnItems( 'hide', items );
20497  if ( !items || !items.length ) {
20498    return;
20499  }
20500  var stagger = this.updateStagger();
20501  items.forEach( function( item, i ) {
20502    item.stagger( i * stagger );
20503    item.hide();
20504  });
20505};
20506
20507/**
20508 * reveal item elements
20509 * @param {Array}, {Element}, {NodeList} items
20510 */
20511proto.revealItemElements = function( elems ) {
20512  var items = this.getItems( elems );
20513  this.reveal( items );
20514};
20515
20516/**
20517 * hide item elements
20518 * @param {Array}, {Element}, {NodeList} items
20519 */
20520proto.hideItemElements = function( elems ) {
20521  var items = this.getItems( elems );
20522  this.hide( items );
20523};
20524
20525/**
20526 * get Outlayer.Item, given an Element
20527 * @param {Element} elem
20528 * @param {Function} callback
20529 * @returns {Outlayer.Item} item
20530 */
20531proto.getItem = function( elem ) {
20532  // loop through items to get the one that matches
20533  for ( var i=0; i < this.items.length; i++ ) {
20534    var item = this.items[i];
20535    if ( item.element == elem ) {
20536      // return item
20537      return item;
20538    }
20539  }
20540};
20541
20542/**
20543 * get collection of Outlayer.Items, given Elements
20544 * @param {Array} elems
20545 * @returns {Array} items - Outlayer.Items
20546 */
20547proto.getItems = function( elems ) {
20548  elems = utils.makeArray( elems );
20549  var items = [];
20550  elems.forEach( function( elem ) {
20551    var item = this.getItem( elem );
20552    if ( item ) {
20553      items.push( item );
20554    }
20555  }, this );
20556
20557  return items;
20558};
20559
20560/**
20561 * remove element(s) from instance and DOM
20562 * @param {Array or NodeList or Element} elems
20563 */
20564proto.remove = function( elems ) {
20565  var removeItems = this.getItems( elems );
20566
20567  this._emitCompleteOnItems( 'remove', removeItems );
20568
20569  // bail if no items to remove
20570  if ( !removeItems || !removeItems.length ) {
20571    return;
20572  }
20573
20574  removeItems.forEach( function( item ) {
20575    item.remove();
20576    // remove item from collection
20577    utils.removeFrom( this.items, item );
20578  }, this );
20579};
20580
20581// ----- destroy ----- //
20582
20583// remove and disable Outlayer instance
20584proto.destroy = function() {
20585  // clean up dynamic styles
20586  var style = this.element.style;
20587  style.height = '';
20588  style.position = '';
20589  style.width = '';
20590  // destroy items
20591  this.items.forEach( function( item ) {
20592    item.destroy();
20593  });
20594
20595  this.unbindResize();
20596
20597  var id = this.element.outlayerGUID;
20598  delete instances[ id ]; // remove reference to instance by id
20599  delete this.element.outlayerGUID;
20600  // remove data for jQuery
20601  if ( jQuery ) {
20602    jQuery.removeData( this.element, this.constructor.namespace );
20603  }
20604
20605};
20606
20607// -------------------------- data -------------------------- //
20608
20609/**
20610 * get Outlayer instance from element
20611 * @param {Element} elem
20612 * @returns {Outlayer}
20613 */
20614Outlayer.data = function( elem ) {
20615  elem = utils.getQueryElement( elem );
20616  var id = elem && elem.outlayerGUID;
20617  return id && instances[ id ];
20618};
20619
20620
20621// -------------------------- create Outlayer class -------------------------- //
20622
20623/**
20624 * create a layout class
20625 * @param {String} namespace
20626 */
20627Outlayer.create = function( namespace, options ) {
20628  // sub-class Outlayer
20629  var Layout = subclass( Outlayer );
20630  // apply new options and compatOptions
20631  Layout.defaults = utils.extend( {}, Outlayer.defaults );
20632  utils.extend( Layout.defaults, options );
20633  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
20634
20635  Layout.namespace = namespace;
20636
20637  Layout.data = Outlayer.data;
20638
20639  // sub-class Item
20640  Layout.Item = subclass( Item );
20641
20642  // -------------------------- declarative -------------------------- //
20643
20644  utils.htmlInit( Layout, namespace );
20645
20646  // -------------------------- jQuery bridge -------------------------- //
20647
20648  // make into jQuery plugin
20649  if ( jQuery && jQuery.bridget ) {
20650    jQuery.bridget( namespace, Layout );
20651  }
20652
20653  return Layout;
20654};
20655
20656function subclass( Parent ) {
20657  function SubClass() {
20658    Parent.apply( this, arguments );
20659  }
20660
20661  SubClass.prototype = Object.create( Parent.prototype );
20662  SubClass.prototype.constructor = SubClass;
20663
20664  return SubClass;
20665}
20666
20667// ----- helpers ----- //
20668
20669// how many milliseconds are in each unit
20670var msUnits = {
20671  ms: 1,
20672  s: 1000
20673};
20674
20675// munge time-like parameter into millisecond number
20676// '0.4s' -> 40
20677function getMilliseconds( time ) {
20678  if ( typeof time == 'number' ) {
20679    return time;
20680  }
20681  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
20682  var num = matches && matches[1];
20683  var unit = matches && matches[2];
20684  if ( !num.length ) {
20685    return 0;
20686  }
20687  num = parseFloat( num );
20688  var mult = msUnits[ unit ] || 1;
20689  return num * mult;
20690}
20691
20692// ----- fin ----- //
20693
20694// back in global
20695Outlayer.Item = Item;
20696
20697return Outlayer;
20698
20699}));
20700
20701/**
20702 * Isotope Item
20703**/
20704
20705( function( window, factory ) {
20706  // universal module definition
20707  /* jshint strict: false */ /*globals define, module, require */
20708  if ( typeof define == 'function' && define.amd ) {
20709    // AMD
20710    define( 'isotope-layout/js/item',[
20711        'outlayer/outlayer'
20712      ],
20713      factory );
20714  } else if ( typeof module == 'object' && module.exports ) {
20715    // CommonJS
20716    module.exports = factory(
20717      require('outlayer')
20718    );
20719  } else {
20720    // browser global
20721    window.Isotope = window.Isotope || {};
20722    window.Isotope.Item = factory(
20723      window.Outlayer
20724    );
20725  }
20726
20727}( window, function factory( Outlayer ) {
20728'use strict';
20729
20730// -------------------------- Item -------------------------- //
20731
20732// sub-class Outlayer Item
20733function Item() {
20734  Outlayer.Item.apply( this, arguments );
20735}
20736
20737var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
20738
20739var _create = proto._create;
20740proto._create = function() {
20741  // assign id, used for original-order sorting
20742  this.id = this.layout.itemGUID++;
20743  _create.call( this );
20744  this.sortData = {};
20745};
20746
20747proto.updateSortData = function() {
20748  if ( this.isIgnored ) {
20749    return;
20750  }
20751  // default sorters
20752  this.sortData.id = this.id;
20753  // for backward compatibility
20754  this.sortData['original-order'] = this.id;
20755  this.sortData.random = Math.random();
20756  // go thru getSortData obj and apply the sorters
20757  var getSortData = this.layout.options.getSortData;
20758  var sorters = this.layout._sorters;
20759  for ( var key in getSortData ) {
20760    var sorter = sorters[ key ];
20761    this.sortData[ key ] = sorter( this.element, this );
20762  }
20763};
20764
20765var _destroy = proto.destroy;
20766proto.destroy = function() {
20767  // call super
20768  _destroy.apply( this, arguments );
20769  // reset display, #741
20770  this.css({
20771    display: ''
20772  });
20773};
20774
20775return Item;
20776
20777}));
20778
20779/**
20780 * Isotope LayoutMode
20781 */
20782
20783( function( window, factory ) {
20784  // universal module definition
20785  /* jshint strict: false */ /*globals define, module, require */
20786  if ( typeof define == 'function' && define.amd ) {
20787    // AMD
20788    define( 'isotope-layout/js/layout-mode',[
20789        'get-size/get-size',
20790        'outlayer/outlayer'
20791      ],
20792      factory );
20793  } else if ( typeof module == 'object' && module.exports ) {
20794    // CommonJS
20795    module.exports = factory(
20796      require('get-size'),
20797      require('outlayer')
20798    );
20799  } else {
20800    // browser global
20801    window.Isotope = window.Isotope || {};
20802    window.Isotope.LayoutMode = factory(
20803      window.getSize,
20804      window.Outlayer
20805    );
20806  }
20807
20808}( window, function factory( getSize, Outlayer ) {
20809  'use strict';
20810
20811  // layout mode class
20812  function LayoutMode( isotope ) {
20813    this.isotope = isotope;
20814    // link properties
20815    if ( isotope ) {
20816      this.options = isotope.options[ this.namespace ];
20817      this.element = isotope.element;
20818      this.items = isotope.filteredItems;
20819      this.size = isotope.size;
20820    }
20821  }
20822
20823  var proto = LayoutMode.prototype;
20824
20825  /**
20826   * some methods should just defer to default Outlayer method
20827   * and reference the Isotope instance as `this`
20828  **/
20829  var facadeMethods = [
20830    '_resetLayout',
20831    '_getItemLayoutPosition',
20832    '_manageStamp',
20833    '_getContainerSize',
20834    '_getElementOffset',
20835    'needsResizeLayout',
20836    '_getOption'
20837  ];
20838
20839  facadeMethods.forEach( function( methodName ) {
20840    proto[ methodName ] = function() {
20841      return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
20842    };
20843  });
20844
20845  // -----  ----- //
20846
20847  // for horizontal layout modes, check vertical size
20848  proto.needsVerticalResizeLayout = function() {
20849    // don't trigger if size did not change
20850    var size = getSize( this.isotope.element );
20851    // check that this.size and size are there
20852    // IE8 triggers resize on body size change, so they might not be
20853    var hasSizes = this.isotope.size && size;
20854    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
20855  };
20856
20857  // ----- measurements ----- //
20858
20859  proto._getMeasurement = function() {
20860    this.isotope._getMeasurement.apply( this, arguments );
20861  };
20862
20863  proto.getColumnWidth = function() {
20864    this.getSegmentSize( 'column', 'Width' );
20865  };
20866
20867  proto.getRowHeight = function() {
20868    this.getSegmentSize( 'row', 'Height' );
20869  };
20870
20871  /**
20872   * get columnWidth or rowHeight
20873   * segment: 'column' or 'row'
20874   * size 'Width' or 'Height'
20875  **/
20876  proto.getSegmentSize = function( segment, size ) {
20877    var segmentName = segment + size;
20878    var outerSize = 'outer' + size;
20879    // columnWidth / outerWidth // rowHeight / outerHeight
20880    this._getMeasurement( segmentName, outerSize );
20881    // got rowHeight or columnWidth, we can chill
20882    if ( this[ segmentName ] ) {
20883      return;
20884    }
20885    // fall back to item of first element
20886    var firstItemSize = this.getFirstItemSize();
20887    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
20888      // or size of container
20889      this.isotope.size[ 'inner' + size ];
20890  };
20891
20892  proto.getFirstItemSize = function() {
20893    var firstItem = this.isotope.filteredItems[0];
20894    return firstItem && firstItem.element && getSize( firstItem.element );
20895  };
20896
20897  // ----- methods that should reference isotope ----- //
20898
20899  proto.layout = function() {
20900    this.isotope.layout.apply( this.isotope, arguments );
20901  };
20902
20903  proto.getSize = function() {
20904    this.isotope.getSize();
20905    this.size = this.isotope.size;
20906  };
20907
20908  // -------------------------- create -------------------------- //
20909
20910  LayoutMode.modes = {};
20911
20912  LayoutMode.create = function( namespace, options ) {
20913
20914    function Mode() {
20915      LayoutMode.apply( this, arguments );
20916    }
20917
20918    Mode.prototype = Object.create( proto );
20919    Mode.prototype.constructor = Mode;
20920
20921    // default options
20922    if ( options ) {
20923      Mode.options = options;
20924    }
20925
20926    Mode.prototype.namespace = namespace;
20927    // register in Isotope
20928    LayoutMode.modes[ namespace ] = Mode;
20929
20930    return Mode;
20931  };
20932
20933  return LayoutMode;
20934
20935}));
20936
20937/*!
20938 * Masonry v4.2.1
20939 * Cascading grid layout library
20940 * https://masonry.desandro.com
20941 * MIT License
20942 * by David DeSandro
20943 */
20944
20945( function( window, factory ) {
20946  // universal module definition
20947  /* jshint strict: false */ /*globals define, module, require */
20948  if ( typeof define == 'function' && define.amd ) {
20949    // AMD
20950    define( 'masonry-layout/masonry',[
20951        'outlayer/outlayer',
20952        'get-size/get-size'
20953      ],
20954      factory );
20955  } else if ( typeof module == 'object' && module.exports ) {
20956    // CommonJS
20957    module.exports = factory(
20958      require('outlayer'),
20959      require('get-size')
20960    );
20961  } else {
20962    // browser global
20963    window.Masonry = factory(
20964      window.Outlayer,
20965      window.getSize
20966    );
20967  }
20968
20969}( window, function factory( Outlayer, getSize ) {
20970
20971
20972
20973// -------------------------- masonryDefinition -------------------------- //
20974
20975  // create an Outlayer layout class
20976  var Masonry = Outlayer.create('masonry');
20977  // isFitWidth -> fitWidth
20978  Masonry.compatOptions.fitWidth = 'isFitWidth';
20979
20980  var proto = Masonry.prototype;
20981
20982  proto._resetLayout = function() {
20983    this.getSize();
20984    this._getMeasurement( 'columnWidth', 'outerWidth' );
20985    this._getMeasurement( 'gutter', 'outerWidth' );
20986    this.measureColumns();
20987
20988    // reset column Y
20989    this.colYs = [];
20990    for ( var i=0; i < this.cols; i++ ) {
20991      this.colYs.push( 0 );
20992    }
20993
20994    this.maxY = 0;
20995    this.horizontalColIndex = 0;
20996  };
20997
20998  proto.measureColumns = function() {
20999    this.getContainerWidth();
21000    // if columnWidth is 0, default to outerWidth of first item
21001    if ( !this.columnWidth ) {
21002      var firstItem = this.items[0];
21003      var firstItemElem = firstItem && firstItem.element;
21004      // columnWidth fall back to item of first element
21005      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
21006        // if first elem has no width, default to size of container
21007        this.containerWidth;
21008    }
21009
21010    var columnWidth = this.columnWidth += this.gutter;
21011
21012    // calculate columns
21013    var containerWidth = this.containerWidth + this.gutter;
21014    var cols = containerWidth / columnWidth;
21015    // fix rounding errors, typically with gutters
21016    var excess = columnWidth - containerWidth % columnWidth;
21017    // if overshoot is less than a pixel, round up, otherwise floor it
21018    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
21019    cols = Math[ mathMethod ]( cols );
21020    this.cols = Math.max( cols, 1 );
21021  };
21022
21023  proto.getContainerWidth = function() {
21024    // container is parent if fit width
21025    var isFitWidth = this._getOption('fitWidth');
21026    var container = isFitWidth ? this.element.parentNode : this.element;
21027    // check that this.size and size are there
21028    // IE8 triggers resize on body size change, so they might not be
21029    var size = getSize( container );
21030    this.containerWidth = size && size.innerWidth;
21031  };
21032
21033  proto._getItemLayoutPosition = function( item ) {
21034    item.getSize();
21035    // how many columns does this brick span
21036    var remainder = item.size.outerWidth % this.columnWidth;
21037    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
21038    // round if off by 1 pixel, otherwise use ceil
21039    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
21040    colSpan = Math.min( colSpan, this.cols );
21041    // use horizontal or top column position
21042    var colPosMethod = this.options.horizontalOrder ?
21043      '_getHorizontalColPosition' : '_getTopColPosition';
21044    var colPosition = this[ colPosMethod ]( colSpan, item );
21045    // position the brick
21046    var position = {
21047      x: this.columnWidth * colPosition.col,
21048      y: colPosition.y
21049    };
21050    // apply setHeight to necessary columns
21051    var setHeight = colPosition.y + item.size.outerHeight;
21052    var setMax = colSpan + colPosition.col;
21053    for ( var i = colPosition.col; i < setMax; i++ ) {
21054      this.colYs[i] = setHeight;
21055    }
21056
21057    return position;
21058  };
21059
21060  proto._getTopColPosition = function( colSpan ) {
21061    var colGroup = this._getTopColGroup( colSpan );
21062    // get the minimum Y value from the columns
21063    var minimumY = Math.min.apply( Math, colGroup );
21064
21065    return {
21066      col: colGroup.indexOf( minimumY ),
21067      y: minimumY,
21068    };
21069  };
21070
21071  /**
21072   * @param {Number} colSpan - number of columns the element spans
21073   * @returns {Array} colGroup
21074   */
21075  proto._getTopColGroup = function( colSpan ) {
21076    if ( colSpan < 2 ) {
21077      // if brick spans only one column, use all the column Ys
21078      return this.colYs;
21079    }
21080
21081    var colGroup = [];
21082    // how many different places could this brick fit horizontally
21083    var groupCount = this.cols + 1 - colSpan;
21084    // for each group potential horizontal position
21085    for ( var i = 0; i < groupCount; i++ ) {
21086      colGroup[i] = this._getColGroupY( i, colSpan );
21087    }
21088    return colGroup;
21089  };
21090
21091  proto._getColGroupY = function( col, colSpan ) {
21092    if ( colSpan < 2 ) {
21093      return this.colYs[ col ];
21094    }
21095    // make an array of colY values for that one group
21096    var groupColYs = this.colYs.slice( col, col + colSpan );
21097    // and get the max value of the array
21098    return Math.max.apply( Math, groupColYs );
21099  };
21100
21101  // get column position based on horizontal index. #873
21102  proto._getHorizontalColPosition = function( colSpan, item ) {
21103    var col = this.horizontalColIndex % this.cols;
21104    var isOver = colSpan > 1 && col + colSpan > this.cols;
21105    // shift to next row if item can't fit on current row
21106    col = isOver ? 0 : col;
21107    // don't let zero-size items take up space
21108    var hasSize = item.size.outerWidth && item.size.outerHeight;
21109    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
21110
21111    return {
21112      col: col,
21113      y: this._getColGroupY( col, colSpan ),
21114    };
21115  };
21116
21117  proto._manageStamp = function( stamp ) {
21118    var stampSize = getSize( stamp );
21119    var offset = this._getElementOffset( stamp );
21120    // get the columns that this stamp affects
21121    var isOriginLeft = this._getOption('originLeft');
21122    var firstX = isOriginLeft ? offset.left : offset.right;
21123    var lastX = firstX + stampSize.outerWidth;
21124    var firstCol = Math.floor( firstX / this.columnWidth );
21125    firstCol = Math.max( 0, firstCol );
21126    var lastCol = Math.floor( lastX / this.columnWidth );
21127    // lastCol should not go over if multiple of columnWidth #425
21128    lastCol -= lastX % this.columnWidth ? 0 : 1;
21129    lastCol = Math.min( this.cols - 1, lastCol );
21130    // set colYs to bottom of the stamp
21131
21132    var isOriginTop = this._getOption('originTop');
21133    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
21134      stampSize.outerHeight;
21135    for ( var i = firstCol; i <= lastCol; i++ ) {
21136      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
21137    }
21138  };
21139
21140  proto._getContainerSize = function() {
21141    this.maxY = Math.max.apply( Math, this.colYs );
21142    var size = {
21143      height: this.maxY
21144    };
21145
21146    if ( this._getOption('fitWidth') ) {
21147      size.width = this._getContainerFitWidth();
21148    }
21149
21150    return size;
21151  };
21152
21153  proto._getContainerFitWidth = function() {
21154    var unusedCols = 0;
21155    // count unused columns
21156    var i = this.cols;
21157    while ( --i ) {
21158      if ( this.colYs[i] !== 0 ) {
21159        break;
21160      }
21161      unusedCols++;
21162    }
21163    // fit container to columns that have been used
21164    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
21165  };
21166
21167  proto.needsResizeLayout = function() {
21168    var previousWidth = this.containerWidth;
21169    this.getContainerWidth();
21170    return previousWidth != this.containerWidth;
21171  };
21172
21173  return Masonry;
21174
21175}));
21176
21177/*!
21178 * Masonry layout mode
21179 * sub-classes Masonry
21180 * https://masonry.desandro.com
21181 */
21182
21183( function( window, factory ) {
21184  // universal module definition
21185  /* jshint strict: false */ /*globals define, module, require */
21186  if ( typeof define == 'function' && define.amd ) {
21187    // AMD
21188    define( 'isotope-layout/js/layout-modes/masonry',[
21189        '../layout-mode',
21190        'masonry-layout/masonry'
21191      ],
21192      factory );
21193  } else if ( typeof module == 'object' && module.exports ) {
21194    // CommonJS
21195    module.exports = factory(
21196      require('../layout-mode'),
21197      require('masonry-layout')
21198    );
21199  } else {
21200    // browser global
21201    factory(
21202      window.Isotope.LayoutMode,
21203      window.Masonry
21204    );
21205  }
21206
21207}( window, function factory( LayoutMode, Masonry ) {
21208'use strict';
21209
21210// -------------------------- masonryDefinition -------------------------- //
21211
21212  // create an Outlayer layout class
21213  var MasonryMode = LayoutMode.create('masonry');
21214
21215  var proto = MasonryMode.prototype;
21216
21217  var keepModeMethods = {
21218    _getElementOffset: true,
21219    layout: true,
21220    _getMeasurement: true
21221  };
21222
21223  // inherit Masonry prototype
21224  for ( var method in Masonry.prototype ) {
21225    // do not inherit mode methods
21226    if ( !keepModeMethods[ method ] ) {
21227      proto[ method ] = Masonry.prototype[ method ];
21228    }
21229  }
21230
21231  var measureColumns = proto.measureColumns;
21232  proto.measureColumns = function() {
21233    // set items, used if measuring first item
21234    this.items = this.isotope.filteredItems;
21235    measureColumns.call( this );
21236  };
21237
21238  // point to mode options for fitWidth
21239  var _getOption = proto._getOption;
21240  proto._getOption = function( option ) {
21241    if ( option == 'fitWidth' ) {
21242      return this.options.isFitWidth !== undefined ?
21243        this.options.isFitWidth : this.options.fitWidth;
21244    }
21245    return _getOption.apply( this.isotope, arguments );
21246  };
21247
21248  return MasonryMode;
21249
21250}));
21251
21252/**
21253 * fitRows layout mode
21254 */
21255
21256( function( window, factory ) {
21257  // universal module definition
21258  /* jshint strict: false */ /*globals define, module, require */
21259  if ( typeof define == 'function' && define.amd ) {
21260    // AMD
21261    define( 'isotope-layout/js/layout-modes/fit-rows',[
21262        '../layout-mode'
21263      ],
21264      factory );
21265  } else if ( typeof exports == 'object' ) {
21266    // CommonJS
21267    module.exports = factory(
21268      require('../layout-mode')
21269    );
21270  } else {
21271    // browser global
21272    factory(
21273      window.Isotope.LayoutMode
21274    );
21275  }
21276
21277}( window, function factory( LayoutMode ) {
21278'use strict';
21279
21280var FitRows = LayoutMode.create('fitRows');
21281
21282var proto = FitRows.prototype;
21283
21284proto._resetLayout = function() {
21285  this.x = 0;
21286  this.y = 0;
21287  this.maxY = 0;
21288  this._getMeasurement( 'gutter', 'outerWidth' );
21289};
21290
21291proto._getItemLayoutPosition = function( item ) {
21292  item.getSize();
21293
21294  var itemWidth = item.size.outerWidth + this.gutter;
21295  // if this element cannot fit in the current row
21296  var containerWidth = this.isotope.size.innerWidth + this.gutter;
21297  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
21298    this.x = 0;
21299    this.y = this.maxY;
21300  }
21301
21302  var position = {
21303    x: this.x,
21304    y: this.y
21305  };
21306
21307  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
21308  this.x += itemWidth;
21309
21310  return position;
21311};
21312
21313proto._getContainerSize = function() {
21314  return { height: this.maxY };
21315};
21316
21317return FitRows;
21318
21319}));
21320
21321/**
21322 * vertical layout mode
21323 */
21324
21325( function( window, factory ) {
21326  // universal module definition
21327  /* jshint strict: false */ /*globals define, module, require */
21328  if ( typeof define == 'function' && define.amd ) {
21329    // AMD
21330    define( 'isotope-layout/js/layout-modes/vertical',[
21331        '../layout-mode'
21332      ],
21333      factory );
21334  } else if ( typeof module == 'object' && module.exports ) {
21335    // CommonJS
21336    module.exports = factory(
21337      require('../layout-mode')
21338    );
21339  } else {
21340    // browser global
21341    factory(
21342      window.Isotope.LayoutMode
21343    );
21344  }
21345
21346}( window, function factory( LayoutMode ) {
21347'use strict';
21348
21349var Vertical = LayoutMode.create( 'vertical', {
21350  horizontalAlignment: 0
21351});
21352
21353var proto = Vertical.prototype;
21354
21355proto._resetLayout = function() {
21356  this.y = 0;
21357};
21358
21359proto._getItemLayoutPosition = function( item ) {
21360  item.getSize();
21361  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
21362    this.options.horizontalAlignment;
21363  var y = this.y;
21364  this.y += item.size.outerHeight;
21365  return { x: x, y: y };
21366};
21367
21368proto._getContainerSize = function() {
21369  return { height: this.y };
21370};
21371
21372return Vertical;
21373
21374}));
21375
21376/*!
21377 * Isotope v3.0.6
21378 *
21379 * Licensed GPLv3 for open source use
21380 * or Isotope Commercial License for commercial use
21381 *
21382 * https://isotope.metafizzy.co
21383 * Copyright 2010-2018 Metafizzy
21384 */
21385
21386( function( window, factory ) {
21387  // universal module definition
21388  /* jshint strict: false */ /*globals define, module, require */
21389  if ( typeof define == 'function' && define.amd ) {
21390    // AMD
21391    define( [
21392        'outlayer/outlayer',
21393        'get-size/get-size',
21394        'desandro-matches-selector/matches-selector',
21395        'fizzy-ui-utils/utils',
21396        'isotope-layout/js/item',
21397        'isotope-layout/js/layout-mode',
21398        // include default layout modes
21399        'isotope-layout/js/layout-modes/masonry',
21400        'isotope-layout/js/layout-modes/fit-rows',
21401        'isotope-layout/js/layout-modes/vertical'
21402      ],
21403      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
21404        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
21405      });
21406  } else if ( typeof module == 'object' && module.exports ) {
21407    // CommonJS
21408    module.exports = factory(
21409      window,
21410      require('outlayer'),
21411      require('get-size'),
21412      require('desandro-matches-selector'),
21413      require('fizzy-ui-utils'),
21414      require('isotope-layout/js/item'),
21415      require('isotope-layout/js/layout-mode'),
21416      // include default layout modes
21417      require('isotope-layout/js/layout-modes/masonry'),
21418      require('isotope-layout/js/layout-modes/fit-rows'),
21419      require('isotope-layout/js/layout-modes/vertical')
21420    );
21421  } else {
21422    // browser global
21423    window.Isotope = factory(
21424      window,
21425      window.Outlayer,
21426      window.getSize,
21427      window.matchesSelector,
21428      window.fizzyUIUtils,
21429      window.Isotope.Item,
21430      window.Isotope.LayoutMode
21431    );
21432  }
21433
21434}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
21435  Item, LayoutMode ) {
21436
21437
21438
21439// -------------------------- vars -------------------------- //
21440
21441var jQuery = window.jQuery;
21442
21443// -------------------------- helpers -------------------------- //
21444
21445var trim = String.prototype.trim ?
21446  function( str ) {
21447    return str.trim();
21448  } :
21449  function( str ) {
21450    return str.replace( /^\s+|\s+$/g, '' );
21451  };
21452
21453// -------------------------- isotopeDefinition -------------------------- //
21454
21455  // create an Outlayer layout class
21456  var Isotope = Outlayer.create( 'isotope', {
21457    layoutMode: 'masonry',
21458    isJQueryFiltering: true,
21459    sortAscending: true
21460  });
21461
21462  Isotope.Item = Item;
21463  Isotope.LayoutMode = LayoutMode;
21464
21465  var proto = Isotope.prototype;
21466
21467  proto._create = function() {
21468    this.itemGUID = 0;
21469    // functions that sort items
21470    this._sorters = {};
21471    this._getSorters();
21472    // call super
21473    Outlayer.prototype._create.call( this );
21474
21475    // create layout modes
21476    this.modes = {};
21477    // start filteredItems with all items
21478    this.filteredItems = this.items;
21479    // keep of track of sortBys
21480    this.sortHistory = [ 'original-order' ];
21481    // create from registered layout modes
21482    for ( var name in LayoutMode.modes ) {
21483      this._initLayoutMode( name );
21484    }
21485  };
21486
21487  proto.reloadItems = function() {
21488    // reset item ID counter
21489    this.itemGUID = 0;
21490    // call super
21491    Outlayer.prototype.reloadItems.call( this );
21492  };
21493
21494  proto._itemize = function() {
21495    var items = Outlayer.prototype._itemize.apply( this, arguments );
21496    // assign ID for original-order
21497    for ( var i=0; i < items.length; i++ ) {
21498      var item = items[i];
21499      item.id = this.itemGUID++;
21500    }
21501    this._updateItemsSortData( items );
21502    return items;
21503  };
21504
21505
21506  // -------------------------- layout -------------------------- //
21507
21508  proto._initLayoutMode = function( name ) {
21509    var Mode = LayoutMode.modes[ name ];
21510    // set mode options
21511    // HACK extend initial options, back-fill in default options
21512    var initialOpts = this.options[ name ] || {};
21513    this.options[ name ] = Mode.options ?
21514      utils.extend( Mode.options, initialOpts ) : initialOpts;
21515    // init layout mode instance
21516    this.modes[ name ] = new Mode( this );
21517  };
21518
21519
21520  proto.layout = function() {
21521    // if first time doing layout, do all magic
21522    if ( !this._isLayoutInited && this._getOption('initLayout') ) {
21523      this.arrange();
21524      return;
21525    }
21526    this._layout();
21527  };
21528
21529  // private method to be used in layout() & magic()
21530  proto._layout = function() {
21531    // don't animate first layout
21532    var isInstant = this._getIsInstant();
21533    // layout flow
21534    this._resetLayout();
21535    this._manageStamps();
21536    this.layoutItems( this.filteredItems, isInstant );
21537
21538    // flag for initalized
21539    this._isLayoutInited = true;
21540  };
21541
21542  // filter + sort + layout
21543  proto.arrange = function( opts ) {
21544    // set any options pass
21545    this.option( opts );
21546    this._getIsInstant();
21547    // filter, sort, and layout
21548
21549    // filter
21550    var filtered = this._filter( this.items );
21551    this.filteredItems = filtered.matches;
21552
21553    this._bindArrangeComplete();
21554
21555    if ( this._isInstant ) {
21556      this._noTransition( this._hideReveal, [ filtered ] );
21557    } else {
21558      this._hideReveal( filtered );
21559    }
21560
21561    this._sort();
21562    this._layout();
21563  };
21564  // alias to _init for main plugin method
21565  proto._init = proto.arrange;
21566
21567  proto._hideReveal = function( filtered ) {
21568    this.reveal( filtered.needReveal );
21569    this.hide( filtered.needHide );
21570  };
21571
21572  // HACK
21573  // Don't animate/transition first layout
21574  // Or don't animate/transition other layouts
21575  proto._getIsInstant = function() {
21576    var isLayoutInstant = this._getOption('layoutInstant');
21577    var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
21578      !this._isLayoutInited;
21579    this._isInstant = isInstant;
21580    return isInstant;
21581  };
21582
21583  // listen for layoutComplete, hideComplete and revealComplete
21584  // to trigger arrangeComplete
21585  proto._bindArrangeComplete = function() {
21586    // listen for 3 events to trigger arrangeComplete
21587    var isLayoutComplete, isHideComplete, isRevealComplete;
21588    var _this = this;
21589    function arrangeParallelCallback() {
21590      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
21591        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
21592      }
21593    }
21594    this.once( 'layoutComplete', function() {
21595      isLayoutComplete = true;
21596      arrangeParallelCallback();
21597    });
21598    this.once( 'hideComplete', function() {
21599      isHideComplete = true;
21600      arrangeParallelCallback();
21601    });
21602    this.once( 'revealComplete', function() {
21603      isRevealComplete = true;
21604      arrangeParallelCallback();
21605    });
21606  };
21607
21608  // -------------------------- filter -------------------------- //
21609
21610  proto._filter = function( items ) {
21611    var filter = this.options.filter;
21612    filter = filter || '*';
21613    var matches = [];
21614    var hiddenMatched = [];
21615    var visibleUnmatched = [];
21616
21617    var test = this._getFilterTest( filter );
21618
21619    // test each item
21620    for ( var i=0; i < items.length; i++ ) {
21621      var item = items[i];
21622      if ( item.isIgnored ) {
21623        continue;
21624      }
21625      // add item to either matched or unmatched group
21626      var isMatched = test( item );
21627      // item.isFilterMatched = isMatched;
21628      // add to matches if its a match
21629      if ( isMatched ) {
21630        matches.push( item );
21631      }
21632      // add to additional group if item needs to be hidden or revealed
21633      if ( isMatched && item.isHidden ) {
21634        hiddenMatched.push( item );
21635      } else if ( !isMatched && !item.isHidden ) {
21636        visibleUnmatched.push( item );
21637      }
21638    }
21639
21640    // return collections of items to be manipulated
21641    return {
21642      matches: matches,
21643      needReveal: hiddenMatched,
21644      needHide: visibleUnmatched
21645    };
21646  };
21647
21648  // get a jQuery, function, or a matchesSelector test given the filter
21649  proto._getFilterTest = function( filter ) {
21650    if ( jQuery && this.options.isJQueryFiltering ) {
21651      // use jQuery
21652      return function( item ) {
21653        return jQuery( item.element ).is( filter );
21654      };
21655    }
21656    if ( typeof filter == 'function' ) {
21657      // use filter as function
21658      return function( item ) {
21659        return filter( item.element );
21660      };
21661    }
21662    // default, use filter as selector string
21663    return function( item ) {
21664      return matchesSelector( item.element, filter );
21665    };
21666  };
21667
21668  // -------------------------- sorting -------------------------- //
21669
21670  /**
21671   * @params {Array} elems
21672   * @public
21673   */
21674  proto.updateSortData = function( elems ) {
21675    // get items
21676    var items;
21677    if ( elems ) {
21678      elems = utils.makeArray( elems );
21679      items = this.getItems( elems );
21680    } else {
21681      // update all items if no elems provided
21682      items = this.items;
21683    }
21684
21685    this._getSorters();
21686    this._updateItemsSortData( items );
21687  };
21688
21689  proto._getSorters = function() {
21690    var getSortData = this.options.getSortData;
21691    for ( var key in getSortData ) {
21692      var sorter = getSortData[ key ];
21693      this._sorters[ key ] = mungeSorter( sorter );
21694    }
21695  };
21696
21697  /**
21698   * @params {Array} items - of Isotope.Items
21699   * @private
21700   */
21701  proto._updateItemsSortData = function( items ) {
21702    // do not update if no items
21703    var len = items && items.length;
21704
21705    for ( var i=0; len && i < len; i++ ) {
21706      var item = items[i];
21707      item.updateSortData();
21708    }
21709  };
21710
21711  // ----- munge sorter ----- //
21712
21713  // encapsulate this, as we just need mungeSorter
21714  // other functions in here are just for munging
21715  var mungeSorter = ( function() {
21716    // add a magic layer to sorters for convienent shorthands
21717    // `.foo-bar` will use the text of .foo-bar querySelector
21718    // `[foo-bar]` will use attribute
21719    // you can also add parser
21720    // `.foo-bar parseInt` will parse that as a number
21721    function mungeSorter( sorter ) {
21722      // if not a string, return function or whatever it is
21723      if ( typeof sorter != 'string' ) {
21724        return sorter;
21725      }
21726      // parse the sorter string
21727      var args = trim( sorter ).split(' ');
21728      var query = args[0];
21729      // check if query looks like [an-attribute]
21730      var attrMatch = query.match( /^\[(.+)\]$/ );
21731      var attr = attrMatch && attrMatch[1];
21732      var getValue = getValueGetter( attr, query );
21733      // use second argument as a parser
21734      var parser = Isotope.sortDataParsers[ args[1] ];
21735      // parse the value, if there was a parser
21736      sorter = parser ? function( elem ) {
21737        return elem && parser( getValue( elem ) );
21738      } :
21739      // otherwise just return value
21740      function( elem ) {
21741        return elem && getValue( elem );
21742      };
21743
21744      return sorter;
21745    }
21746
21747    // get an attribute getter, or get text of the querySelector
21748    function getValueGetter( attr, query ) {
21749      // if query looks like [foo-bar], get attribute
21750      if ( attr ) {
21751        return function getAttribute( elem ) {
21752          return elem.getAttribute( attr );
21753        };
21754      }
21755
21756      // otherwise, assume its a querySelector, and get its text
21757      return function getChildText( elem ) {
21758        var child = elem.querySelector( query );
21759        return child && child.textContent;
21760      };
21761    }
21762
21763    return mungeSorter;
21764  })();
21765
21766  // parsers used in getSortData shortcut strings
21767  Isotope.sortDataParsers = {
21768    'parseInt': function( val ) {
21769      return parseInt( val, 10 );
21770    },
21771    'parseFloat': function( val ) {
21772      return parseFloat( val );
21773    }
21774  };
21775
21776  // ----- sort method ----- //
21777
21778  // sort filteredItem order
21779  proto._sort = function() {
21780    if ( !this.options.sortBy ) {
21781      return;
21782    }
21783    // keep track of sortBy History
21784    var sortBys = utils.makeArray( this.options.sortBy );
21785    if ( !this._getIsSameSortBy( sortBys ) ) {
21786      // concat all sortBy and sortHistory, add to front, oldest goes in last
21787      this.sortHistory = sortBys.concat( this.sortHistory );
21788    }
21789    // sort magic
21790    var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
21791    this.filteredItems.sort( itemSorter );
21792  };
21793
21794  // check if sortBys is same as start of sortHistory
21795  proto._getIsSameSortBy = function( sortBys ) {
21796    for ( var i=0; i < sortBys.length; i++ ) {
21797      if ( sortBys[i] != this.sortHistory[i] ) {
21798        return false;
21799      }
21800    }
21801    return true;
21802  };
21803
21804  // returns a function used for sorting
21805  function getItemSorter( sortBys, sortAsc ) {
21806    return function sorter( itemA, itemB ) {
21807      // cycle through all sortKeys
21808      for ( var i = 0; i < sortBys.length; i++ ) {
21809        var sortBy = sortBys[i];
21810        var a = itemA.sortData[ sortBy ];
21811        var b = itemB.sortData[ sortBy ];
21812        if ( a > b || a < b ) {
21813          // if sortAsc is an object, use the value given the sortBy key
21814          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
21815          var direction = isAscending ? 1 : -1;
21816          return ( a > b ? 1 : -1 ) * direction;
21817        }
21818      }
21819      return 0;
21820    };
21821  }
21822
21823  // -------------------------- methods -------------------------- //
21824
21825  // get layout mode
21826  proto._mode = function() {
21827    var layoutMode = this.options.layoutMode;
21828    var mode = this.modes[ layoutMode ];
21829    if ( !mode ) {
21830      // TODO console.error
21831      throw new Error( 'No layout mode: ' + layoutMode );
21832    }
21833    // HACK sync mode's options
21834    // any options set after init for layout mode need to be synced
21835    mode.options = this.options[ layoutMode ];
21836    return mode;
21837  };
21838
21839  proto._resetLayout = function() {
21840    // trigger original reset layout
21841    Outlayer.prototype._resetLayout.call( this );
21842    this._mode()._resetLayout();
21843  };
21844
21845  proto._getItemLayoutPosition = function( item  ) {
21846    return this._mode()._getItemLayoutPosition( item );
21847  };
21848
21849  proto._manageStamp = function( stamp ) {
21850    this._mode()._manageStamp( stamp );
21851  };
21852
21853  proto._getContainerSize = function() {
21854    return this._mode()._getContainerSize();
21855  };
21856
21857  proto.needsResizeLayout = function() {
21858    return this._mode().needsResizeLayout();
21859  };
21860
21861  // -------------------------- adding & removing -------------------------- //
21862
21863  // HEADS UP overwrites default Outlayer appended
21864  proto.appended = function( elems ) {
21865    var items = this.addItems( elems );
21866    if ( !items.length ) {
21867      return;
21868    }
21869    // filter, layout, reveal new items
21870    var filteredItems = this._filterRevealAdded( items );
21871    // add to filteredItems
21872    this.filteredItems = this.filteredItems.concat( filteredItems );
21873  };
21874
21875  // HEADS UP overwrites default Outlayer prepended
21876  proto.prepended = function( elems ) {
21877    var items = this._itemize( elems );
21878    if ( !items.length ) {
21879      return;
21880    }
21881    // start new layout
21882    this._resetLayout();
21883    this._manageStamps();
21884    // filter, layout, reveal new items
21885    var filteredItems = this._filterRevealAdded( items );
21886    // layout previous items
21887    this.layoutItems( this.filteredItems );
21888    // add to items and filteredItems
21889    this.filteredItems = filteredItems.concat( this.filteredItems );
21890    this.items = items.concat( this.items );
21891  };
21892
21893  proto._filterRevealAdded = function( items ) {
21894    var filtered = this._filter( items );
21895    this.hide( filtered.needHide );
21896    // reveal all new items
21897    this.reveal( filtered.matches );
21898    // layout new items, no transition
21899    this.layoutItems( filtered.matches, true );
21900    return filtered.matches;
21901  };
21902
21903  /**
21904   * Filter, sort, and layout newly-appended item elements
21905   * @param {Array or NodeList or Element} elems
21906   */
21907  proto.insert = function( elems ) {
21908    var items = this.addItems( elems );
21909    if ( !items.length ) {
21910      return;
21911    }
21912    // append item elements
21913    var i, item;
21914    var len = items.length;
21915    for ( i=0; i < len; i++ ) {
21916      item = items[i];
21917      this.element.appendChild( item.element );
21918    }
21919    // filter new stuff
21920    var filteredInsertItems = this._filter( items ).matches;
21921    // set flag
21922    for ( i=0; i < len; i++ ) {
21923      items[i].isLayoutInstant = true;
21924    }
21925    this.arrange();
21926    // reset flag
21927    for ( i=0; i < len; i++ ) {
21928      delete items[i].isLayoutInstant;
21929    }
21930    this.reveal( filteredInsertItems );
21931  };
21932
21933  var _remove = proto.remove;
21934  proto.remove = function( elems ) {
21935    elems = utils.makeArray( elems );
21936    var removeItems = this.getItems( elems );
21937    // do regular thing
21938    _remove.call( this, elems );
21939    // bail if no items to remove
21940    var len = removeItems && removeItems.length;
21941    // remove elems from filteredItems
21942    for ( var i=0; len && i < len; i++ ) {
21943      var item = removeItems[i];
21944      // remove item from collection
21945      utils.removeFrom( this.filteredItems, item );
21946    }
21947  };
21948
21949  proto.shuffle = function() {
21950    // update random sortData
21951    for ( var i=0; i < this.items.length; i++ ) {
21952      var item = this.items[i];
21953      item.sortData.random = Math.random();
21954    }
21955    this.options.sortBy = 'random';
21956    this._sort();
21957    this._layout();
21958  };
21959
21960  /**
21961   * trigger fn without transition
21962   * kind of hacky to have this in the first place
21963   * @param {Function} fn
21964   * @param {Array} args
21965   * @returns ret
21966   * @private
21967   */
21968  proto._noTransition = function( fn, args ) {
21969    // save transitionDuration before disabling
21970    var transitionDuration = this.options.transitionDuration;
21971    // disable transition
21972    this.options.transitionDuration = 0;
21973    // do it
21974    var returnValue = fn.apply( this, args );
21975    // re-enable transition for reveal
21976    this.options.transitionDuration = transitionDuration;
21977    return returnValue;
21978  };
21979
21980  // ----- helper methods ----- //
21981
21982  /**
21983   * getter method for getting filtered item elements
21984   * @returns {Array} elems - collection of item elements
21985   */
21986  proto.getFilteredItemElements = function() {
21987    return this.filteredItems.map( function( item ) {
21988      return item.element;
21989    });
21990  };
21991
21992  // -----  ----- //
21993
21994  return Isotope;
21995
21996}));
21997
21998/*!
21999 * Packery layout mode PACKAGED v2.0.1
22000 * sub-classes Packery
22001 */
22002
22003/**
22004 * Rect
22005 * low-level utility class for basic geometry
22006 */
22007
22008( function( window, factory ) {
22009  // universal module definition
22010  /* jshint strict: false */ /* globals define, module */
22011  if ( typeof define == 'function' && define.amd ) {
22012    // AMD
22013    define( 'packery/js/rect',factory );
22014  } else if ( typeof module == 'object' && module.exports ) {
22015    // CommonJS
22016    module.exports = factory();
22017  } else {
22018    // browser global
22019    window.Packery = window.Packery || {};
22020    window.Packery.Rect = factory();
22021  }
22022
22023}( window, function factory() {
22024
22025
22026// -------------------------- Rect -------------------------- //
22027
22028function Rect( props ) {
22029  // extend properties from defaults
22030  for ( var prop in Rect.defaults ) {
22031    this[ prop ] = Rect.defaults[ prop ];
22032  }
22033
22034  for ( prop in props ) {
22035    this[ prop ] = props[ prop ];
22036  }
22037
22038}
22039
22040Rect.defaults = {
22041  x: 0,
22042  y: 0,
22043  width: 0,
22044  height: 0
22045};
22046
22047var proto = Rect.prototype;
22048
22049/**
22050 * Determines whether or not this rectangle wholly encloses another rectangle or point.
22051 * @param {Rect} rect
22052 * @returns {Boolean}
22053**/
22054proto.contains = function( rect ) {
22055  // points don't have width or height
22056  var otherWidth = rect.width || 0;
22057  var otherHeight = rect.height || 0;
22058  return this.x <= rect.x &&
22059    this.y <= rect.y &&
22060    this.x + this.width >= rect.x + otherWidth &&
22061    this.y + this.height >= rect.y + otherHeight;
22062};
22063
22064/**
22065 * Determines whether or not the rectangle intersects with another.
22066 * @param {Rect} rect
22067 * @returns {Boolean}
22068**/
22069proto.overlaps = function( rect ) {
22070  var thisRight = this.x + this.width;
22071  var thisBottom = this.y + this.height;
22072  var rectRight = rect.x + rect.width;
22073  var rectBottom = rect.y + rect.height;
22074
22075  // http://stackoverflow.com/a/306332
22076  return this.x < rectRight &&
22077    thisRight > rect.x &&
22078    this.y < rectBottom &&
22079    thisBottom > rect.y;
22080};
22081
22082/**
22083 * @param {Rect} rect - the overlapping rect
22084 * @returns {Array} freeRects - rects representing the area around the rect
22085**/
22086proto.getMaximalFreeRects = function( rect ) {
22087
22088  // if no intersection, return false
22089  if ( !this.overlaps( rect ) ) {
22090    return false;
22091  }
22092
22093  var freeRects = [];
22094  var freeRect;
22095
22096  var thisRight = this.x + this.width;
22097  var thisBottom = this.y + this.height;
22098  var rectRight = rect.x + rect.width;
22099  var rectBottom = rect.y + rect.height;
22100
22101  // top
22102  if ( this.y < rect.y ) {
22103    freeRect = new Rect({
22104      x: this.x,
22105      y: this.y,
22106      width: this.width,
22107      height: rect.y - this.y
22108    });
22109    freeRects.push( freeRect );
22110  }
22111
22112  // right
22113  if ( thisRight > rectRight ) {
22114    freeRect = new Rect({
22115      x: rectRight,
22116      y: this.y,
22117      width: thisRight - rectRight,
22118      height: this.height
22119    });
22120    freeRects.push( freeRect );
22121  }
22122
22123  // bottom
22124  if ( thisBottom > rectBottom ) {
22125    freeRect = new Rect({
22126      x: this.x,
22127      y: rectBottom,
22128      width: this.width,
22129      height: thisBottom - rectBottom
22130    });
22131    freeRects.push( freeRect );
22132  }
22133
22134  // left
22135  if ( this.x < rect.x ) {
22136    freeRect = new Rect({
22137      x: this.x,
22138      y: this.y,
22139      width: rect.x - this.x,
22140      height: this.height
22141    });
22142    freeRects.push( freeRect );
22143  }
22144
22145  return freeRects;
22146};
22147
22148proto.canFit = function( rect ) {
22149  return this.width >= rect.width && this.height >= rect.height;
22150};
22151
22152return Rect;
22153
22154}));
22155
22156/**
22157 * Packer
22158 * bin-packing algorithm
22159 */
22160
22161( function( window, factory ) {
22162  // universal module definition
22163  /* jshint strict: false */ /* globals define, module, require */
22164  if ( typeof define == 'function' && define.amd ) {
22165    // AMD
22166    define( 'packery/js/packer',[ './rect' ], factory );
22167  } else if ( typeof module == 'object' && module.exports ) {
22168    // CommonJS
22169    module.exports = factory(
22170      require('./rect')
22171    );
22172  } else {
22173    // browser global
22174    var Packery = window.Packery = window.Packery || {};
22175    Packery.Packer = factory( Packery.Rect );
22176  }
22177
22178}( window, function factory( Rect ) {
22179
22180
22181// -------------------------- Packer -------------------------- //
22182
22183/**
22184 * @param {Number} width
22185 * @param {Number} height
22186 * @param {String} sortDirection
22187 *   topLeft for vertical, leftTop for horizontal
22188 */
22189function Packer( width, height, sortDirection ) {
22190  this.width = width || 0;
22191  this.height = height || 0;
22192  this.sortDirection = sortDirection || 'downwardLeftToRight';
22193
22194  this.reset();
22195}
22196
22197var proto = Packer.prototype;
22198
22199proto.reset = function() {
22200  this.spaces = [];
22201
22202  var initialSpace = new Rect({
22203    x: 0,
22204    y: 0,
22205    width: this.width,
22206    height: this.height
22207  });
22208
22209  this.spaces.push( initialSpace );
22210  // set sorter
22211  this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
22212};
22213
22214// change x and y of rect to fit with in Packer's available space
22214s
22215proto.pack = function( rect ) {
22216  for ( var i=0; i < this.spaces.length; i++ ) {
22217    var space = this.spaces[i];
22218    if ( space.canFit( rect ) ) {
22219      this.placeInSpace( rect, space );
22220      break;
22221    }
22222  }
22223};
22224
22225proto.columnPack = function( rect ) {
22226  for ( var i=0; i < this.spaces.length; i++ ) {
22227    var space = this.spaces[i];
22228    var canFitInSpaceColumn = space.x <= rect.x &&
22229      space.x + space.width >= rect.x + rect.width &&
22230      space.height >= rect.height - 0.01; // fudge number for rounding error
22231    if ( canFitInSpaceColumn ) {
22232      rect.y = space.y;
22233      this.placed( rect );
22234      break;
22235    }
22236  }
22237};
22238
22239proto.rowPack = function( rect ) {
22240  for ( var i=0; i < this.spaces.length; i++ ) {
22241    var space = this.spaces[i];
22242    var canFitInSpaceRow = space.y <= rect.y &&
22243      space.y + space.height >= rect.y + rect.height &&
22244      space.width >= rect.width - 0.01; // fudge number for rounding error
22245    if ( canFitInSpaceRow ) {
22246      rect.x = space.x;
22247      this.placed( rect );
22248      break;
22249    }
22250  }
22251};
22252
22253proto.placeInSpace = function( rect, space ) {
22254  // place rect in space
22255  rect.x = space.x;
22256  rect.y = space.y;
22257
22258  this.placed( rect );
22259};
22260
22261// update spaces with placed rect
22262proto.placed = function( rect ) {
22263  // update spaces
22264  var revisedSpaces = [];
22265  for ( var i=0; i < this.spaces.length; i++ ) {
22266    var space = this.spaces[i];
22267    var newSpaces = space.getMaximalFreeRects( rect );
22268    // add either the original space or the new spaces to the revised spaces
22269    if ( newSpaces ) {
22270      revisedSpaces.push.apply( revisedSpaces, newSpaces );
22271    } else {
22272      revisedSpaces.push( space );
22273    }
22274  }
22275
22276  this.spaces = revisedSpaces;
22277
22278  this.mergeSortSpaces();
22279};
22280
22281proto.mergeSortSpaces = function() {
22282  // remove redundant spaces
22283  Packer.mergeRects( this.spaces );
22284  this.spaces.sort( this.sorter );
22285};
22286
22287// add a space back
22288proto.addSpace = function( rect ) {
22289  this.spaces.push( rect );
22290  this.mergeSortSpaces();
22291};
22292
22293// -------------------------- utility functions -------------------------- //
22294
22295/**
22296 * Remove redundant rectangle from array of rectangles
22297 * @param {Array} rects: an array of Rects
22298 * @returns {Array} rects: an array of Rects
22299**/
22300Packer.mergeRects = function( rects ) {
22301  var i = 0;
22302  var rect = rects[i];
22303
22304  rectLoop:
22305  while ( rect ) {
22306    var j = 0;
22307    var compareRect = rects[ i + j ];
22308
22309    while ( compareRect ) {
22310      if  ( compareRect == rect ) {
22311        j++; // next
22312      } else if ( compareRect.contains( rect ) ) {
22313        // remove rect
22314        rects.splice( i, 1 );
22315        rect = rects[i]; // set next rect
22316        continue rectLoop; // bail on compareLoop
22317      } else if ( rect.contains( compareRect ) ) {
22318        // remove compareRect
22319        rects.splice( i + j, 1 );
22320      } else {
22321        j++;
22322      }
22323      compareRect = rects[ i + j ]; // set next compareRect
22324    }
22325    i++;
22326    rect = rects[i];
22327  }
22328
22329  return rects;
22330};
22331
22332
22333// -------------------------- sorters -------------------------- //
22334
22335// functions for sorting rects in order
22336var sorters = {
22337  // top down, then left to right
22338  downwardLeftToRight: function( a, b ) {
22339    return a.y - b.y || a.x - b.x;
22340  },
22341  // left to right, then top down
22342  rightwardTopToBottom: function( a, b ) {
22343    return a.x - b.x || a.y - b.y;
22344  }
22345};
22346
22347
22348// --------------------------  -------------------------- //
22349
22350return Packer;
22351
22352}));
22353
22354/**
22355 * Packery Item Element
22356**/
22357
22358( function( window, factory ) {
22359  // universal module definition
22360  /* jshint strict: false */ /* globals define, module, require */
22361  if ( typeof define == 'function' && define.amd ) {
22362    // AMD
22363    define( 'packery/js/item',[
22364        'outlayer/outlayer',
22365        './rect'
22366      ],
22367      factory );
22368  } else if ( typeof module == 'object' && module.exports ) {
22369    // CommonJS
22370    module.exports = factory(
22371      require('outlayer'),
22372      require('./rect')
22373    );
22374  } else {
22375    // browser global
22376    window.Packery.Item = factory(
22377      window.Outlayer,
22378      window.Packery.Rect
22379    );
22380  }
22381
22382}( window, function factory( Outlayer, Rect ) {
22383
22384
22385// -------------------------- Item -------------------------- //
22386
22387var docElemStyle = document.documentElement.style;
22388
22389var transformProperty = typeof docElemStyle.transform == 'string' ?
22390  'transform' : 'WebkitTransform';
22391
22392// sub-class Item
22393var Item = function PackeryItem() {
22394  Outlayer.Item.apply( this, arguments );
22395};
22396
22397var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
22398
22399var __create = proto._create;
22400proto._create = function() {
22401  // call default _create logic
22402  __create.call( this );
22403  this.rect = new Rect();
22404};
22405
22406var _moveTo = proto.moveTo;
22407proto.moveTo = function( x, y ) {
22408  // don't shift 1px while dragging
22409  var dx = Math.abs( this.position.x - x );
22410  var dy = Math.abs( this.position.y - y );
22411
22412  var canHackGoTo = this.layout.dragItemCount && !this.isPlacing &&
22413    !this.isTransitioning && dx < 1 && dy < 1;
22414  if ( canHackGoTo ) {
22415    this.goTo( x, y );
22416    return;
22417  }
22418  _moveTo.apply( this, arguments );
22419};
22420
22421// -------------------------- placing -------------------------- //
22422
22423proto.enablePlacing = function() {
22424  this.removeTransitionStyles();
22425  // remove transform property from transition
22426  if ( this.isTransitioning && transformProperty ) {
22427    this.element.style[ transformProperty ] = 'none';
22428  }
22429  this.isTransitioning = false;
22430  this.getSize();
22431  this.layout._setRectSize( this.element, this.rect );
22432  this.isPlacing = true;
22433};
22434
22435proto.disablePlacing = function() {
22436  this.isPlacing = false;
22437};
22438
22439// -----  ----- //
22440
22441// remove element from DOM
22442proto.removeElem = function() {
22443  this.element.parentNode.removeChild( this.element );
22444  // add space back to packer
22445  this.layout.packer.addSpace( this.rect );
22446  this.emitEvent( 'remove', [ this ] );
22447};
22448
22449// ----- dropPlaceholder ----- //
22450
22451proto.showDropPlaceholder = function() {
22452  var dropPlaceholder = this.dropPlaceholder;
22453  if ( !dropPlaceholder ) {
22454    // create dropPlaceholder
22455    dropPlaceholder = this.dropPlaceholder = document.createElement('div');
22456    dropPlaceholder.className = 'packery-drop-placeholder';
22457    dropPlaceholder.style.position = 'absolute';
22458  }
22459
22460  dropPlaceholder.style.width = this.size.width + 'px';
22461  dropPlaceholder.style.height = this.size.height + 'px';
22462  this.positionDropPlaceholder();
22463  this.layout.element.appendChild( dropPlaceholder );
22464};
22465
22466proto.positionDropPlaceholder = function() {
22467  this.dropPlaceholder.style[ transformProperty ] = 'translate(' +
22468    this.rect.x + 'px, ' + this.rect.y + 'px)';
22469};
22470
22471proto.hideDropPlaceholder = function() {
22472  this.layout.element.removeChild( this.dropPlaceholder );
22473};
22474
22475// -----  ----- //
22476
22477return Item;
22478
22479}));
22480
22481/*!
22482 * Packery v2.0.0
22483 * Gapless, draggable grid layouts
22484 *
22485 * Licensed GPLv3 for open source use
22486 * or Packery Commercial License for commercial use
22487 *
22488 * http://packery.metafizzy.co
22489 * Copyright 2016 Metafizzy
22490 */
22491
22492( function( window, factory ) {
22493  // universal module definition
22494  /* jshint strict: false */ /* globals define, module, require */
22495  if ( typeof define == 'function' && define.amd ) {
22496    // AMD
22497    define( 'packery/js/packery',[
22498        'get-size/get-size',
22499        'outlayer/outlayer',
22500        './rect',
22501        './packer',
22502        './item'
22503      ],
22504      factory );
22505  } else if ( typeof module == 'object' && module.exports ) {
22506    // CommonJS
22507    module.exports = factory(
22508      require('get-size'),
22509      require('outlayer'),
22510      require('./rect'),
22511      require('./packer'),
22512      require('./item')
22513    );
22514  } else {
22515    // browser global
22516    window.Packery = factory(
22517      window.getSize,
22518      window.Outlayer,
22519      window.Packery.Rect,
22520      window.Packery.Packer,
22521      window.Packery.Item
22522    );
22523  }
22524
22525}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) {
22526
22527
22528// ----- Rect ----- //
22529
22530// allow for pixel rounding errors IE8-IE11 & Firefox; #227
22531Rect.prototype.canFit = function( rect ) {
22532  return this.width >= rect.width - 1 && this.height >= rect.height - 1;
22533};
22534
22535// -------------------------- Packery -------------------------- //
22536
22537// create an Outlayer layout class
22538var Packery = Outlayer.create('packery');
22539Packery.Item = Item;
22540
22541var proto = Packery.prototype;
22542
22543proto._create = function() {
22544  // call super
22545  Outlayer.prototype._create.call( this );
22546
22547  // initial properties
22548  this.packer = new Packer();
22549  // packer for drop targets
22550  this.shiftPacker = new Packer();
22551  this.isEnabled = true;
22552
22553  this.dragItemCount = 0;
22554
22555  // create drag handlers
22556  var _this = this;
22557  this.handleDraggabilly = {
22558    dragStart: function() {
22559      _this.itemDragStart( this.element );
22560    },
22561    dragMove: function() {
22562      _this.itemDragMove( this.element, this.position.x, this.position.y );
22563    },
22564    dragEnd: function() {
22565      _this.itemDragEnd( this.element );
22566    }
22567  };
22568
22569  this.handleUIDraggable = {
22570    start: function handleUIDraggableStart( event, ui ) {
22571      // HTML5 may trigger dragstart, dismiss HTML5 dragging
22572      if ( !ui ) {
22573        return;
22574      }
22575      _this.itemDragStart( event.currentTarget );
22576    },
22577    drag: function handleUIDraggableDrag( event, ui ) {
22578      if ( !ui ) {
22579        return;
22580      }
22581      _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
22582    },
22583    stop: function handleUIDraggableStop( event, ui ) {
22584      if ( !ui ) {
22585        return;
22586      }
22587      _this.itemDragEnd( event.currentTarget );
22588    }
22589  };
22590
22591};
22592
22593
22594// ----- init & layout ----- //
22595
22596/**
22597 * logic before any new layout
22598 */
22599proto._resetLayout = function() {
22600  this.getSize();
22601
22602  this._getMeasurements();
22603
22604  // reset packer
22605  var width, height, sortDirection;
22606  // packer settings, if horizontal or vertical
22607  if ( this._getOption('horizontal') ) {
22608    width = Infinity;
22609    height = this.size.innerHeight + this.gutter;
22610    sortDirection = 'rightwardTopToBottom';
22611  } else {
22612    width = this.size.innerWidth + this.gutter;
22613    height = Infinity;
22614    sortDirection = 'downwardLeftToRight';
22615  }
22616
22617  this.packer.width = this.shiftPacker.width = width;
22618  this.packer.height = this.shiftPacker.height = height;
22619  this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection;
22620
22621  this.packer.reset();
22622
22623  // layout
22624  this.maxY = 0;
22625  this.maxX = 0;
22626};
22627
22628/**
22629 * update columnWidth, rowHeight, & gutter
22630 * @private
22631 */
22632proto._getMeasurements = function() {
22633  this._getMeasurement( 'columnWidth', 'width' );
22634  this._getMeasurement( 'rowHeight', 'height' );
22635  this._getMeasurement( 'gutter', 'width' );
22636};
22637
22638proto._getItemLayoutPosition = function( item ) {
22639  this._setRectSize( item.element, item.rect );
22640  if ( this.isShifting || this.dragItemCount > 0 ) {
22641    var packMethod = this._getPackMethod();
22642    this.packer[ packMethod ]( item.rect );
22643  } else {
22644    this.packer.pack( item.rect );
22645  }
22646
22647  this._setMaxXY( item.rect );
22648  return item.rect;
22649};
22650
22651proto.shiftLayout = function() {
22652  this.isShifting = true;
22653  this.layout();
22654  delete this.isShifting;
22655};
22656
22657proto._getPackMethod = function() {
22658  return this._getOption('horizontal') ? 'rowPack' : 'columnPack';
22659};
22660
22661
22662/**
22663 * set max X and Y value, for size of container
22664 * @param {Packery.Rect} rect
22665 * @private
22666 */
22667proto._setMaxXY = function( rect ) {
22668  this.maxX = Math.max( rect.x + rect.width, this.maxX );
22669  this.maxY = Math.max( rect.y + rect.height, this.maxY );
22670};
22671
22672/**
22673 * set the width and height of a rect, applying columnWidth and rowHeight
22674 * @param {Element} elem
22675 * @param {Packery.Rect} rect
22676 */
22677proto._setRectSize = function( elem, rect ) {
22678  var size = getSize( elem );
22679  var w = size.outerWidth;
22680  var h = size.outerHeight;
22681  // size for columnWidth and rowHeight, if available
22682  // only check if size is non-zero, #177
22683  if ( w || h ) {
22684    w = this._applyGridGutter( w, this.columnWidth );
22685    h = this._applyGridGutter( h, this.rowHeight );
22686  }
22687  // rect must fit in packer
22688  rect.width = Math.min( w, this.packer.width );
22689  rect.height = Math.min( h, this.packer.height );
22690};
22691
22692/**
22693 * fits item to columnWidth/rowHeight and adds gutter
22694 * @param {Number} measurement - item width or height
22695 * @param {Number} gridSize - columnWidth or rowHeight
22696 * @returns measurement
22697 */
22698proto._applyGridGutter = function( measurement, gridSize ) {
22699  // just add gutter if no gridSize
22700  if ( !gridSize ) {
22701    return measurement + this.gutter;
22702  }
22703  gridSize += this.gutter;
22704  // fit item to columnWidth/rowHeight
22705  var remainder = measurement % gridSize;
22706  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
22707  measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
22708  return measurement;
22709};
22710
22711proto._getContainerSize = function() {
22712  if ( this._getOption('horizontal') ) {
22713    return {
22714      width: this.maxX - this.gutter
22715    };
22716  } else {
22717    return {
22718      height: this.maxY - this.gutter
22719    };
22720  }
22721};
22722
22723
22724// -------------------------- stamp -------------------------- //
22725
22726/**
22727 * makes space for element
22728 * @param {Element} elem
22729 */
22730proto._manageStamp = function( elem ) {
22731
22732  var item = this.getItem( elem );
22733  var rect;
22734  if ( item && item.isPlacing ) {
22735    rect = item.rect;
22736  } else {
22737    var offset = this._getElementOffset( elem );
22738    rect = new Rect({
22739      x: this._getOption('originLeft') ? offset.left : offset.right,
22740      y: this._getOption('originTop') ? offset.top : offset.bottom
22741    });
22742  }
22743
22744  this._setRectSize( elem, rect );
22745  // save its space in the packer
22746  this.packer.placed( rect );
22747  this._setMaxXY( rect );
22748};
22749
22750// -------------------------- methods -------------------------- //
22751
22752function verticalSorter( a, b ) {
22753  return a.position.y - b.position.y || a.position.x - b.position.x;
22754}
22755
22756function horizontalSorter( a, b ) {
22757  return a.position.x - b.position.x || a.position.y - b.position.y;
22758}
22759
22760proto.sortItemsByPosition = function() {
22761  var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter;
22762  this.items.sort( sorter );
22763};
22764
22765/**
22766 * Fit item element in its current position
22767 * Packery will position elements around it
22768 * useful for expanding elements
22769 *
22770 * @param {Element} elem
22771 * @param {Number} x - horizontal destination position, optional
22772 * @param {Number} y - vertical destination position, optional
22773 */
22774proto.fit = function( elem, x, y ) {
22775  var item = this.getItem( elem );
22776  if ( !item ) {
22777    return;
22778  }
22779
22780  // stamp item to get it out of layout
22781  this.stamp( item.element );
22782  // set placing flag
22783  item.enablePlacing();
22784  this.updateShiftTargets( item );
22785  // fall back to current position for fitting
22786  x = x === undefined ? item.rect.x: x;
22787  y = y === undefined ? item.rect.y: y;
22788  // position it best at its destination
22789  this.shift( item, x, y );
22790  this._bindFitEvents( item );
22791  item.moveTo( item.rect.x, item.rect.y );
22792  // layout everything else
22793  this.shiftLayout();
22794  // return back to regularly scheduled programming
22795  this.unstamp( item.element );
22796  this.sortItemsByPosition();
22797  item.disablePlacing();
22798};
22799
22800/**
22801 * emit event when item is fit and other items are laid out
22802 * @param {Packery.Item} item
22803 * @private
22804 */
22805proto._bindFitEvents = function( item ) {
22806  var _this = this;
22807  var ticks = 0;
22808  function onLayout() {
22809    ticks++;
22810    if ( ticks != 2 ) {
22811      return;
22812    }
22813    _this.dispatchEvent( 'fitComplete', null, [ item ] );
22814  }
22815  // when item is laid out
22816  item.once( 'layout', onLayout );
22817  // when all items are laid out
22818  this.once( 'layoutComplete', onLayout );
22819};
22820
22821// -------------------------- resize -------------------------- //
22822
22823// debounced, layout on resize
22824proto.resize = function() {
22825  // don't trigger if size did not change
22826  // or if resize was unbound. See #285, outlayer#9
22827  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
22828    return;
22829  }
22830
22831  if ( this.options.shiftPercentResize ) {
22832    this.resizeShiftPercentLayout();
22833  } else {
22834    this.layout();
22835  }
22836};
22837
22838/**
22839 * check if layout is needed post layout
22840 * @returns Boolean
22841 */
22842proto.needsResizeLayout = function() {
22843  var size = getSize( this.element );
22844  var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth';
22845  return size[ innerSize ] != this.size[ innerSize ];
22846};
22847
22848proto.resizeShiftPercentLayout = function() {
22849  var items = this._getItemsForLayout( this.items );
22850
22851  var isHorizontal = this._getOption('horizontal');
22852  var coord = isHorizontal ? 'y' : 'x';
22853  var measure = isHorizontal ? 'height' : 'width';
22854  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
22855  var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth';
22856
22857  // proportional re-align items
22858  var previousSegment = this[ segmentName ];
22859  previousSegment = previousSegment && previousSegment + this.gutter;
22860
22861  if ( previousSegment ) {
22862    this._getMeasurements();
22863    var currentSegment = this[ segmentName ] + this.gutter;
22864    items.forEach( function( item ) {
22865      var seg = Math.round( item.rect[ coord ] / previousSegment );
22866      item.rect[ coord ] = seg * currentSegment;
22867    });
22868  } else {
22869    var currentSize = getSize( this.element )[ innerSize ] + this.gutter;
22870    var previousSize = this.packer[ measure ];
22871    items.forEach( function( item ) {
22872      item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize;
22873    });
22874  }
22875
22876  this.shiftLayout();
22877};
22878
22879// -------------------------- drag -------------------------- //
22880
22881/**
22882 * handle an item drag start event
22883 * @param {Element} elem
22884 */
22885proto.itemDragStart = function( elem ) {
22886  if ( !this.isEnabled ) {
22887    return;
22888  }
22889  this.stamp( elem );
22890  // this.ignore( elem );
22891  var item = this.getItem( elem );
22892  if ( !item ) {
22893    return;
22894  }
22895
22896  item.enablePlacing();
22897  item.showDropPlaceholder();
22898  this.dragItemCount++;
22899  this.updateShiftTargets( item );
22900};
22901
22902proto.updateShiftTargets = function( dropItem ) {
22903  this.shiftPacker.reset();
22904
22905  // pack stamps
22906  this._getBoundingRect();
22907  var isOriginLeft = this._getOption('originLeft');
22908  var isOriginTop = this._getOption('originTop');
22909  this.stamps.forEach( function( stamp ) {
22910    // ignore dragged item
22911    var item = this.getItem( stamp );
22912    if ( item && item.isPlacing ) {
22913      return;
22914    }
22915    var offset = this._getElementOffset( stamp );
22916    var rect = new Rect({
22917      x: isOriginLeft ? offset.left : offset.right,
22918      y: isOriginTop ? offset.top : offset.bottom
22919    });
22920    this._setRectSize( stamp, rect );
22921    // save its space in the packer
22922    this.shiftPacker.placed( rect );
22923  }, this );
22924
22925  // reset shiftTargets
22926  var isHorizontal = this._getOption('horizontal');
22927  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
22928  var measure = isHorizontal ? 'height' : 'width';
22929
22930  this.shiftTargetKeys = [];
22931  this.shiftTargets = [];
22932  var boundsSize;
22933  var segment = this[ segmentName ];
22934  segment = segment && segment + this.gutter;
22935
22936  if ( segment ) {
22937    var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment );
22938    var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment );
22939    boundsSize = ( segs - segmentSpan ) * segment;
22940    // add targets on top
22941    for ( var i=0; i < segs; i++ ) {
22942      this._addShiftTarget( i * segment, 0, boundsSize );
22943    }
22944  } else {
22945    boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ];
22946    this._addShiftTarget( 0, 0, boundsSize );
22947  }
22948
22949  // pack each item to measure where shiftTargets are
22950  var items = this._getItemsForLayout( this.items );
22951  var packMethod = this._getPackMethod();
22952  items.forEach( function( item ) {
22953    var rect = item.rect;
22954    this._setRectSize( item.element, rect );
22955    this.shiftPacker[ packMethod ]( rect );
22956
22957    // add top left corner
22958    this._addShiftTarget( rect.x, rect.y, boundsSize );
22959    // add bottom left / top right corner
22960    var cornerX = isHorizontal ? rect.x + rect.width : rect.x;
22961    var cornerY = isHorizontal ? rect.y : rect.y + rect.height;
22962    this._addShiftTarget( cornerX, cornerY, boundsSize );
22963
22964    if ( segment ) {
22965      // add targets for each column on bottom / row on right
22966      var segSpan = Math.round( rect[ measure ] / segment );
22967      for ( var i=1; i < segSpan; i++ ) {
22968        var segX = isHorizontal ? cornerX : rect.x + segment * i;
22969        var segY = isHorizontal ? rect.y + segment * i : cornerY;
22970        this._addShiftTarget( segX, segY, boundsSize );
22971      }
22972    }
22973  }, this );
22974
22975};
22976
22977proto._addShiftTarget = function( x, y, boundsSize ) {
22978  var checkCoord = this._getOption('horizontal') ? y : x;
22979  if ( checkCoord !== 0 && checkCoord > boundsSize ) {
22980    return;
22981  }
22982  // create string for a key, easier to keep track of what targets
22983  var key = x + ',' + y;
22984  var hasKey = this.shiftTargetKeys.indexOf( key ) != -1;
22985  if ( hasKey ) {
22986    return;
22987  }
22988  this.shiftTargetKeys.push( key );
22989  this.shiftTargets.push({ x: x, y: y });
22990};
22991
22992// -------------------------- drop -------------------------- //
22993
22994proto.shift = function( item, x, y ) {
22995  var shiftPosition;
22996  var minDistance = Infinity;
22997  var position = { x: x, y: y };
22998  this.shiftTargets.forEach( function( target ) {
22999    var distance = getDistance( target, position );
23000    if ( distance < minDistance ) {
23001      shiftPosition = target;
23002      minDistance = distance;
23003    }
23004  });
23005  item.rect.x = shiftPosition.x;
23006  item.rect.y = shiftPosition.y;
23007};
23008
23009function getDistance( a, b ) {
23010  var dx = b.x - a.x;
23011  var dy = b.y - a.y;
23012  return Math.sqrt( dx * dx + dy * dy );
23013}
23014
23015// -------------------------- drag move -------------------------- //
23016
23017var DRAG_THROTTLE_TIME = 120;
23018
23019/**
23020 * handle an item drag move event
23021 * @param {Element} elem
23022 * @param {Number} x - horizontal change in position
23023 * @param {Number} y - vertical change in position
23024 */
23025proto.itemDragMove = function( elem, x, y ) {
23026  var item = this.isEnabled && this.getItem( elem );
23027  if ( !item ) {
23028    return;
23029  }
23030
23031  x -= this.size.paddingLeft;
23032  y -= this.size.paddingTop;
23033
23034  var _this = this;
23035  function onDrag() {
23036    _this.shift( item, x, y );
23037    item.positionDropPlaceholder();
23038    _this.layout();
23039  }
23040
23041  // throttle
23042  var now = new Date();
23043  if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) {
23044    clearTimeout( this.dragTimeout );
23045    this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME );
23046  } else {
23047    onDrag();
23048    this._itemDragTime = now;
23049  }
23050};
23051
23052// -------------------------- drag end -------------------------- //
23053
23054/**
23055 * handle an item drag end event
23056 * @param {Element} elem
23057 */
23058proto.itemDragEnd = function( elem ) {
23059  var item = this.isEnabled && this.getItem( elem );
23060  if ( !item ) {
23061    return;
23062  }
23063
23064  clearTimeout( this.dragTimeout );
23065  item.element.classList.add('is-positioning-post-drag');
23066
23067  var completeCount = 0;
23068  var _this = this;
23069  function onDragEndLayoutComplete() {
23070    completeCount++;
23071    if ( completeCount != 2 ) {
23072      return;
23073    }
23074    // reset drag item
23075    item.element.classList.remove('is-positioning-post-drag');
23076    item.hideDropPlaceholder();
23077    _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
23078  }
23079
23080  item.once( 'layout', onDragEndLayoutComplete );
23081  this.once( 'layoutComplete', onDragEndLayoutComplete );
23082  item.moveTo( item.rect.x, item.rect.y );
23083  this.layout();
23084  this.dragItemCount = Math.max( 0, this.dragItemCount - 1 );
23085  this.sortItemsByPosition();
23086  item.disablePlacing();
23087  this.unstamp( item.element );
23088};
23089
23090/**
23091 * binds Draggabilly events
23092 * @param {Draggabilly} draggie
23093 */
23094proto.bindDraggabillyEvents = function( draggie ) {
23095  this._bindDraggabillyEvents( draggie, 'on' );
23096};
23097
23098proto.unbindDraggabillyEvents = function( draggie ) {
23099  this._bindDraggabillyEvents( draggie, 'off' );
23100};
23101
23102proto._bindDraggabillyEvents = function( draggie, method ) {
23103  var handlers = this.handleDraggabilly;
23104  draggie[ method ]( 'dragStart', handlers.dragStart );
23105  draggie[ method ]( 'dragMove', handlers.dragMove );
23106  draggie[ method ]( 'dragEnd', handlers.dragEnd );
23107};
23108
23109/**
23110 * binds jQuery UI Draggable events
23111 * @param {jQuery} $elems
23112 */
23113proto.bindUIDraggableEvents = function( $elems ) {
23114  this._bindUIDraggableEvents( $elems, 'on' );
23115};
23116
23117proto.unbindUIDraggableEvents = function( $elems ) {
23118  this._bindUIDraggableEvents( $elems, 'off' );
23119};
23120
23121proto._bindUIDraggableEvents = function( $elems, method ) {
23122  var handlers = this.handleUIDraggable;
23123  $elems
23124    [ method ]( 'dragstart', handlers.start )
23125    [ method ]( 'drag', handlers.drag )
23126    [ method ]( 'dragstop', handlers.stop );
23127};
23128
23129// ----- destroy ----- //
23130
23131var _destroy = proto.destroy;
23132proto.destroy = function() {
23133  _destroy.apply( this, arguments );
23134  // disable flag; prevent drag events from triggering. #72
23135  this.isEnabled = false;
23136};
23137
23138// -----  ----- //
23139
23140Packery.Rect = Rect;
23141Packery.Packer = Packer;
23142
23143return Packery;
23144
23145}));
23146
23147/*!
23148 * Packery layout mode v2.0.1
23149 * sub-classes Packery
23150 */
23151
23152/*jshint browser: true, strict: true, undef: true, unused: true */
23153
23154( function( window, factory ) {
23155
23156  // universal module definition
23157  if ( typeof define == 'function' && define.amd ) {
23158    // AMD
23159    define( [
23160        'isotope-layout/js/layout-mode',
23161        'packery/js/packery'
23162      ],
23163      factory );
23164  } else if ( typeof module == 'object' && module.exports ) {
23165    // CommonJS
23166    module.exports = factory(
23167      require('isotope-layout/js/layout-mode'),
23168      require('packery')
23169    );
23170  } else {
23171    // browser global
23172    factory(
23173      window.Isotope.LayoutMode,
23174      window.Packery
23175    );
23176  }
23177
23178}( window, function factor( LayoutMode, Packery ) {
23179
23180
23181  // create an Outlayer layout class
23182  var PackeryMode = LayoutMode.create('packery');
23183  var proto = PackeryMode.prototype;
23184
23185  var keepModeMethods = {
23186    _getElementOffset: true,
23187    _getMeasurement: true
23188  };
23189
23190  // inherit Packery prototype
23191  for ( var method in Packery.prototype ) {
23192    // do not inherit mode methods
23193    if ( !keepModeMethods[ method ] ) {
23194      proto[ method ] = Packery.prototype[ method ];
23195    }
23196  }
23197
23198  // set packer in _resetLayout
23199  var _resetLayout = proto._resetLayout;
23200  proto._resetLayout = function() {
23201    this.packer = this.packer || new Packery.Packer();
23202    this.shiftPacker = this.shiftPacker || new Packery.Packer();
23203    _resetLayout.apply( this, arguments );
23204  };
23205
23206  var _getItemLayoutPosition = proto._getItemLayoutPosition;
23207  proto._getItemLayoutPosition = function( item ) {
23208    // set packery rect
23209    item.rect = item.rect || new Packery.Rect();
23210    return _getItemLayoutPosition.call( this, item );
23211  };
23212
23213  // needsResizeLayout for vertical or horizontal
23214  var _needsResizeLayout = proto.needsResizeLayout;
23215  proto.needsResizeLayout = function() {
23216    if ( this._getOption('horizontal') ) {
23217      return this.needsVerticalResizeLayout();
23218    } else {
23219      return _needsResizeLayout.call( this );
23220    }
23221  };
23222
23223  // point to mode options for horizontal
23224  var _getOption = proto._getOption;
23225  proto._getOption = function( option ) {
23226    if ( option == 'horizontal' ) {
23227      return this.options.isHorizontal !== undefined ?
23228        this.options.isHorizontal : this.options.horizontal;
23229    }
23230    return _getOption.apply( this.isotope, arguments );
23231  };
23232
23233  return PackeryMode;
23234
23235}));
23236
23237/*!
23238 * cellsByRows layout mode for Isotope
23239 * v1.1.3
23240 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html
23241 */
23242
23243/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */
23244
23245( function( window, factory ) {
23246  // universal module definition
23247  /* jshint strict: false */ /*globals define, module, require */
23248  if ( typeof define === 'function' && define.amd ) {
23249    // AMD
23250    define( [
23251        'isotope/js/layout-mode'
23252      ],
23253      factory );
23254  } else if ( typeof exports === 'object' ) {
23255    // CommonJS
23256    module.exports = factory(
23257      require('isotope-layout/js/layout-mode')
23258    );
23259  } else {
23260    // browser global
23261    factory(
23262      window.Isotope.LayoutMode
23263    );
23264  }
23265
23266}( window, function factory( LayoutMode ) {
23267  'use strict';
23268
23269  var CellsByRow = LayoutMode.create( 'cellsByRow' );
23270  var proto = CellsByRow.prototype;
23271
23272  proto._resetLayout = function() {
23273    // reset properties
23274    this.itemIndex = 0;
23275    // measurements
23276    this.getColumnWidth();
23277    this.getRowHeight();
23278    // set cols
23279    this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth );
23280    this.cols = Math.max( this.cols, 1 );
23281  };
23282
23283  proto._getItemLayoutPosition = function( item ) {
23284    item.getSize();
23285    var col = this.itemIndex % this.cols;
23286    var row = Math.floor( this.itemIndex / this.cols );
23287    // center item within cell
23288    var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2;
23289    var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2;
23290    this.itemIndex++;
23291    return { x: x, y: y };
23292  };
23293
23294  proto._getContainerSize = function() {
23295    return {
23296      height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight
23297    };
23298  };
23299
23300  return CellsByRow;
23301
23302}));
23303/*global jQuery: true */
23304
23305/*!
23306   --------------------------------
23307   Infinite Scroll
23308   --------------------------------
23309   + https://github.com/paulirish/infinite-scroll
23310   + version 2.1.0
23311   + Copyright 2011/12 Paul Irish & Luke Shumard
23312   + Licensed under the MIT license
23313
23314   + Documentation: http://infinite-scroll.com/
23315*/
23316
23317// Uses AMD or browser globals to create a jQuery plugin.
23318(function (factory) {
23319	if (typeof define === 'function' && define.amd) {
23320		// AMD. Register as an anonymous module.
23321		define(['jquery'], factory);
23322	} else {
23323		// Browser globals
23324		factory(jQuery);
23325	}
23326}(function ($, undefined) {
23327	'use strict';
23328
23329	$.infinitescroll = function infscr(options, callback, element) {
23330		this.element = $(element);
23331
23332		// Flag the object in the event of a failed creation
23333		if (!this._create(options, callback)) {
23334			this.failed = true;
23335		}
23336	};
23337
23338	$.infinitescroll.defaults = {
23339		loading: {
23340			finished: undefined,
23341			finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>",
23342			img: 'data:image/gif;base64,R0lGODlh3AATAPQeAPDy+MnQ6LW/4N3h8MzT6rjC4sTM5r/I5NHX7N7j8c7U6tvg8OLl8uXo9Ojr9b3G5MfP6Ovu9tPZ7PT1+vX2+tbb7vf4+8/W69jd7rC73vn5/O/x+K243ai02////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQECgD/ACwAAAAA3AATAAAF/6AnjmRpnmiqrmzrvnAsz3Rt33iu73zv/8CgcEj0BAScpHLJbDqf0Kh0Sq1ar9isdioItAKGw+MAKYMFhbF63CW438f0mg1R2O8EuXj/aOPtaHx7fn96goR4hmuId4qDdX95c4+RBIGCB4yAjpmQhZN0YGYGXitdZBIVGAsLoq4BBKQDswm1CQRkcG6ytrYKubq8vbfAcMK9v7q7EMO1ycrHvsW6zcTKsczNz8HZw9vG3cjTsMIYqQkCLBwHCgsMDQ4RDAYIqfYSFxDxEfz88/X38Onr16+Bp4ADCco7eC8hQYMAEe57yNCew4IVBU7EGNDiRn8Z831cGLHhSIgdFf9chIeBg7oA7gjaWUWTVQAGE3LqBDCTlc9WOHfm7PkTqNCh54rePDqB6M+lR536hCpUqs2gVZM+xbrTqtGoWqdy1emValeXKzggYBBB5y1acFNZmEvXAoN2cGfJrTv3bl69Ffj2xZt3L1+/fw3XRVw4sGDGcR0fJhxZsF3KtBTThZxZ8mLMgC3fRatCbYMNFCzwLEqLgE4NsDWs/tvqdezZf13Hvk2A9Szdu2X3pg18N+68xXn7rh1c+PLksI/Dhe6cuO3ow3NfV92bdArTqC2Ebd3A8vjf5QWfH6Bg7Nz17c2fj69+fnq+8N2Lty+fuP78/eV2X13neIcCeBRwxorbZrA1ANoCDGrgoG8RTshahQ9iSKEEzUmYIYfNWViUhheCGJyIP5E4oom7WWjgCeBFAJNv1DVV01MAdJhhjdkplWNzO/5oXI846njjVEIqR2OS2B1pE5PVscajkxhMycqLJghQSwT40PgfAl4GqNSXYdZXJn5gSkmmmmJu1aZYb14V51do+pTOCmA40AqVCIhG5IJ9PvYnhIFOxmdqhpaI6GeHCtpooisuutmg+Eg62KOMKuqoTaXgicQWoIYq6qiklmoqFV0UoeqqrLbq6quwxirrrLTWauutJ4QAACH5BAUKABwALAcABADOAAsAAAX/IPd0D2dyRCoUp/k8gpHOKtseR9yiSmGbuBykler9XLAhkbDavXTL5k2oqFqNOxzUZPU5YYZd1XsD72rZpBjbeh52mSNnMSC8lwblKZGwi+0QfIJ8CncnCoCDgoVnBHmKfByGJimPkIwtiAeBkH6ZHJaKmCeVnKKTHIihg5KNq4uoqmEtcRUtEREMBggtEr4QDrjCuRC8h7/BwxENeicSF8DKy82pyNLMOxzWygzFmdvD2L3P0dze4+Xh1Arkyepi7dfFvvTtLQkZBC0T/FX3CRgCMOBHsJ+EHYQY7OinAGECgQsB+Lu3AOK+CewcWjwxQeJBihtNGHSoQOE+iQ3//4XkwBBhRZMcUS6YSXOAwIL8PGqEaSJCiYt9SNoCmnJPAgUVLChdaoFBURN8MAzl2PQphwQLfDFd6lTowglHve6rKpbjhK7/pG5VinZP1qkiz1rl4+tr2LRwWU64cFEihwEtZgbgR1UiHaMVvxpOSwBA37kzGz9e8G+B5MIEKLutOGEsAH2ATQwYfTmuX8aETWdGPZmiZcccNSzeTCA1Sw0bdiitC7LBWgu8jQr8HRzqgpK6gX88QbrB14z/kF+ELpwB8eVQj/JkqdylAudji/+ts3039vEEfK8Vz2dlvxZKG0CmbkKDBvllRd6fCzDvBLKBDSCeffhRJEFebFk1k/Mv9jVIoIJZSeBggwUaNeB+Qk34IE0cXlihcfRxkOAJFFhwGmKlmWDiakZhUJtnLBpnWWcnKaAZcxI0piFGGLBm1mc90kajSCveeBVWKeYEoU2wqeaQi0PetoE+rr14EpVC7oAbAUHqhYExbn2XHHsVqbcVew9tx8+XJKk5AZsqqdlddGpqAKdbAYBn1pcczmSTdWvdmZ17c1b3FZ99vnTdCRFM8OEcAhLwm1NdXnWcBBSMRWmfkWZqVlsmLIiAp/o1gGV2vpS4lalGYsUOqXrddcKCmK61aZ8SjEpUpVFVoCpTj4r661Km7kBHjrDyc1RAIQAAIfkEBQoAGwAsBwAEAM4ACwAABf/gtmUCd4goQQgFKj6PYKi0yrrbc8i4ohQt12EHcal+MNSQiCP8gigdz7iCioaCIvUmZLp8QBzW0EN2vSlCuDtFKaq4RyHzQLEKZNdiQDhRDVooCwkbfm59EAmKi4SGIm+AjIsKjhsqB4mSjT2IOIOUnICeCaB/mZKFNTSRmqVpmJqklSqskq6PfYYCDwYHDC4REQwGCBLGxxIQDsHMwhAIX8bKzcENgSLGF9PU1j3Sy9zX2NrgzQziChLk1BHWxcjf7N046tvN82715czn9Pryz6Ilc4ACj4EBOCZM8KEnAYYADBRKnACAYUMFv1wotIhCEcaJCisqwJFgAUSQGyX/kCSVUUTIdKMwJlyo0oXHlhskwrTJciZHEXsgaqS4s6PJiCAr1uzYU8kBBSgnWFqpoMJMUjGtDmUwkmfVmVypakWhEKvXsS4nhLW5wNjVroJIoc05wSzTr0PtiigpYe4EC2vj4iWrFu5euWIMRBhacaVJhYQBEFjA9jHjyQ0xEABwGceGAZYjY0YBOrRLCxUp29QM+bRkx5s7ZyYgVbTqwwti2ybJ+vLtDYpycyZbYOlptxdx0kV+V7lC5iJAyyRrwYKxAdiz82ng0/jnAdMJFz0cPi104Ec1Vj9/M6F173vKL/feXv156dw11tlqeMMnv4V5Ap53GmjQQH97nFfg+IFiucfgRX5Z8KAgbUlQ4IULIlghhhdOSB6AgX0IVn8eReghen3NRIBsRgnH4l4LuEidZBjwRpt6NM5WGwoW0KSjCwX6yJSMab2GwwAPDXfaBCtWpluRTQqC5JM5oUZAjUNS+VeOLWpJEQ7VYQANW0INJSZVDFSnZphjSikfmzE5N4EEbQI1QJmnWXCmHulRp2edwDXF43txukenJwvI9xyg9Q26Z3MzGUcBYFEChZh6DVTq34AU8Iflh51Sd+CnKFYQ6mmZkhqfBKfSxZWqA9DZanWjxmhrWwi0qtCrt/43K6WqVjjpmhIqgEGvculaGKklKstAACEAACH5BAUKABwALAcABADOAAsAAAX/ICdyQmaMYyAUqPgIBiHPxNpy79kqRXH8wAPsRmDdXpAWgWdEIYm2llCHqjVHU+jjJkwqBTecwItShMXkEfNWSh8e1NGAcLgpDGlRgk7EJ/6Ae3VKfoF/fDuFhohVeDeCfXkcCQqDVQcQhn+VNDOYmpSWaoqBlUSfmowjEA+iEAEGDRGztAwGCDcXEA60tXEiCrq8vREMEBLIyRLCxMWSH
23342MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/Cpk3ABwSLQkYAQwT/P309vcI7OvXr94jBQMJ/nskkGA/BQBRLNDncAIAiDcG6LsxAWOLiQzmeURBKWSLCQbv/1F0eDGinJUKR47YY1IEgQASKk7Yc7ACRwZm7mHweRJoz59BJUogisKCUaFMR0x4SlJBVBFTk8pZivTR0K73rN5wqlXEAq5Fy3IYgHbEzQ0nLy4QSoCjXLoom96VOJEeCosK5n4kkFfqXjl94wa+l1gvAcGICbewAOAxY8l/Ky/QhAGz4cUkGxu2HNozhwMGBnCUqUdBg9UuW9eUynqSwLHIBujePef1ZGQZXcM+OFuEBeBhi3OYgLyqcuaxbT9vLkf4SeqyWxSQpKGB2gQpm1KdWbu72rPRzR9Ne2Nu9Kzr/1Jqj0yD/fvqP4aXOt5sW/5qsXXVcv1Nsp8IBUAmgswGF3llGgeU1YVXXKTN1FlhWFXW3gIE+DVChApysACHHo7Q4A35lLichh+ROBmLKAzgYmYEYDAhCgxKGOOMn4WR4kkDaoBBOxJtdNKQxFmg5JIWIBnQc07GaORfUY4AEkdV6jHlCEISSZ5yTXpp1pbGZbkWmcuZmQCaE6iJ0FhjMaDjTMsgZaNEHFRAQVp3bqXnZED1qYcECOz5V6BhSWCoVJQIKuKQi2KFKEkEFAqoAo7uYSmO3jk61wUUMKmknJ4SGimBmAa0qVQBhAAAIfkEBQoAGwAsBwAEAM4ACwAABf/gJm5FmRlEqhJC+bywgK5pO4rHI0D3pii22+Mg6/0Ej96weCMAk7cDkXf7lZTTnrMl7eaYoy10JN0ZFdco0XAuvKI6qkgVFJXYNwjkIBcNBgR8TQoGfRsJCRuCYYQQiI+ICosiCoGOkIiKfSl8mJkHZ4U9kZMbKaI3pKGXmJKrngmug4WwkhA0lrCBWgYFCCMQFwoQDRHGxwwGCBLMzRLEx8iGzMMO0cYNeCMKzBDW19lnF9DXDIY/48Xg093f0Q3s1dcR8OLe8+Y91OTv5wrj7o7B+7VNQqABIoRVCMBggsOHE36kSoCBIcSH3EbFangxogJYFi8CkJhqQciLJEf/LDDJEeJIBT0GsOwYUYJGBS0fjpQAMidGmyVP6sx4Y6VQhzs9VUwkwqaCCh0tmKoFtSMDmBOf9phg4SrVrROuasRQAaxXpVUhdsU6IsECZlvX3kwLUWzRt0BHOLTbNlbZG3vZinArge5Dvn7wbqtQkSYAAgtKmnSsYKVKo2AfW048uaPmG386i4Q8EQMBAIAnfB7xBxBqvapJ9zX9WgRS2YMpnvYMGdPK3aMjt/3dUcNI4blpj7iwkMFWDXDvSmgAlijrt9RTR78+PS6z1uAJZIe93Q8g5zcsWCi/4Y+C8bah5zUv3vv89uft30QP23punGCx5954oBBwnwYaNCDY/wYrsYeggnM9B2Fpf8GG2CEUVWhbWAtGouEGDy7Y4IEJVrbSiXghqGKIo7z1IVcXIkKWWR361QOLWWnIhwERpLaaCCee5iMBGJQmJGyPFTnbkfHVZGRtIGrg5HALEJAZbu39BuUEUmq1JJQIPtZilY5hGeSWsSk52G9XqsmgljdIcABytq13HyIM6RcUA+r1qZ4EBF3WHWB29tBgAzRhEGhig8KmqKFv8SeCeo+mgsF7YFXa1qWSbkDpom/mqR1PmHCqJ3fwNRVXjC7S6CZhFVCQ2lWvZiirhQq42SACt25IK2hv8TprriUV1usGgeka7LFcNmCldMLi6qZMgFLgpw16Cipb7bC1knXsBiEAACH5BAUKABsALAcABADOAAsAAAX/4FZsJPkUmUGsLCEUTywXglFuSg7fW1xAvNWLF6sFFcPb42C8EZCj24EJdCp2yoegWsolS0Uu6fmamg8n8YYcLU2bXSiRaXMGvqV6/KAeJAh8VgZqCX+BexCFioWAYgqNi4qAR4ORhRuHY408jAeUhAmYYiuVlpiflqGZa5CWkzc5fKmbbhIpsAoQDRG8vQwQCBLCwxK6vb5qwhfGxxENahvCEA7NzskSy7vNzzzK09W/PNHF1NvX2dXcN8K55cfh69Luveol3vO8zwi4Yhj+AQwmCBw4IYclDAAJDlQggVOChAoLKkgFkSCAHDwWLKhIEOONARsDKryogFPIiAUb/95gJNIiw4wnI778GFPhzBKFOAq8qLJEhQpiNArjMcHCmlTCUDIouTKBhApELSxFWiGiVKY4E2CAekPgUphDu0742nRrVLJZnyrFSqKQ2ohoSYAMW6IoDpNJ4bLdILTnAj8KUF7UeENjAKuDyxIgOuGiOI0EBBMgLNew5AUrDTMGsFixwBIaNCQuAXJB57qNJ2OWm2Aj4skwCQCIyNkhhtMkdsIuodE0AN4LJDRgfLPtn5YDLdBlraAByuUbBgxQwICxMOnYpVOPej074OFdlfc0TqC62OIbcppHjV4o+LrieWhfT8JC/I/T6W8oCl29vQ0XjLdBaA3s1RcPBO7lFvpX8BVoG4O5jTXRQRDuJ6FDTzEWF1/BCZhgbyAKE9qICYLloQYOFtahVRsWYlZ4KQJHlwHS/IYaZ6sZd9tmu5HQm2xi1UaTbzxYwJk/wBF5g5EEYOBZeEfGZmNdFyFZmZIR4jikbLThlh5kUUVJGmRT7sekkziRWUIACABk3T4qCsedgO4xhgGcY7q5pHJ4klBBTQRJ0CeHcoYHHUh6wgfdn9uJdSdMiebGJ0zUPTcoS286FCkrZxnYoYYKWLkBowhQoBeaOlZAgVhLidrXqg2G
23342iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/oGFw2WZuT5oZROsSQnGaKjRvilI893MItlNOJ5v5gDcFrHhKIWcEYu/xFEqNv6B1N62aclysF7fsZYe5aOx2yL5aAUGSaT1oTYMBwQ5VGCAJgYIJCnx1gIOBhXdwiIl7d0p2iYGQUAQBjoOFSQR/lIQHnZ+Ue6OagqYzSqSJi5eTpTxGcjcSChANEbu8DBAIEsHBChe5vL13G7fFuscRDcnKuM3H0La3EA7Oz8kKEsXazr7Cw9/Gztar5uHHvte47MjktznZ2w0G1+D3BgirAqJmJMAQgMGEgwgn5Ei0gKDBhBMALGRYEOJBb5QcWlQo4cbAihZz3GgIMqFEBSM1/4ZEOWPAgpIIJXYU+PIhRG8ja1qU6VHlzZknJNQ6UanCjQkWCIGSUGEjAwVLjc44+DTqUQtPPS5gejUrTa5TJ3g9sWCr1BNUWZI161StiQUDmLYdGfesibQ3XMq1OPYthrwuA2yU2LBs2cBHIypYQPPlYAKFD5cVvNPtW8eVGbdcQADATsiNO4cFAPkvHpedPzc8kUcPgNGgZ5RNDZG05reoE9s2vSEP79MEGiQGy1qP8LA4ZcdtsJE48ONoLTBtTV0B9LsTnPceoIDBDQvS7W7vfjVY3q3eZ4A339J4eaAmKqU/sV58HvJh2RcnIBsDUw0ABqhBA5aV5V9XUFGiHfVeAiWwoFgJJrIXRH1tEMiDFV4oHoAEGlaWhgIGSGBO2nFomYY3mKjVglidaNYJGJDkWW2xxTfbjCbVaOGNqoX2GloR8ZeTaECS9pthRGJH2g0b3Agbk6hNANtteHD2GJUucfajCQBy5OOTQ25ZgUPvaVVQmbKh9510/qQpwXx3SQdfk8tZJOd5b6JJFplT3ZnmmX3qd5l1eg5q00HrtUkUn0AKaiGjClSAgKLYZcgWXwocGRcCFGCKwSB6ceqphwmYRUFYT/1WKlOdUpipmxW0mlCqHjYkAaeoZlqrqZ4qd+upQKaapn/AmgAegZ8KUtYtFAQQAgAh+QQFCgAbACwHAAQAzgALAAAF/+C2PUcmiCiZGUTrEkKBis8jQEquKwU5HyXIbEPgyX7BYa5wTNmEMwWsSXsqFbEh8DYs9mrgGjdK6GkPY5GOeU6ryz7UFopSQEzygOGhJBjoIgMDBAcBM0V/CYqLCQqFOwobiYyKjn2TlI6GKC2YjJZknouaZAcQlJUHl6eooJwKooobqoewrJSEmyKdt59NhRKFMxLEEA4RyMkMEAjDEhfGycqAG8TQx9IRDRDE3d3R2ctD1RLg0ttKEnbY5wZD3+zJ6M7X2RHi9Oby7u/r9g38UFjTh2xZJBEBMDAboogAgwkQI07IMUORwocSJwCgWDFBAIwZOaJIsOBjRogKJP8wTODw5ESVHVtm3AhzpEeQElOuNDlTZ0ycEUWKWFASqEahGwYUPbnxoAgEdlYSqDBkgoUNClAlIHbSAoOsqCRQnQHxq1axVb06FWFxLIqyaze0Tft1JVqyE+pWXMD1pF6bYl3+HTqAWNW8cRUFzmih0ZAAB2oGKukSAAGGRHWJgLiR6AylBLpuHKKUMlMCngMpDSAa9QIUggZVVvDaJobLeC3XZpvgNgCmtPcuwP3WgmXSq4do0DC6o2/guzcseECtUoO0hmcsGKDgOt7ssBd07wqesAIGZC1YIBa7PQHvb1+SFo+++HrJSQfB33xfav3i5eX3Hnb4CTJgegEq8tH/YQEOcIJzbm2G2EoYRLgBXFpVmFYDcREV4HIcnmUhiGBRouEMJGJGzHIspqgdXxK0yCKHRNXoIX4uorCdTyjkyNtdPWrA4Up82EbAbzMRxxZRR54WXVLDIRmRcag5d2R6ugl3ZXzNhTecchpMhIGVAKAYpgJjjsSklBEd99maZoo535ZvdamjBEpusJyctg3h4X8XqodBMx0tiNeg/oGJaKGABpogS40KSqiaEgBqlQWLUtqoVQnytekEjzo0hHqhRorppOZt2p923M2AAV+oBtpAnnPNoB6HaU6mAAIU+IXmi3j2mtFXuUoHKwXpzVrsjcgGOauKEjQrwq157hitGq2NoWmjh7z6Wmxb0m5w66+2VRAuXN/yFUAIACH5BAUKABsALAcABADOAAsAAAX/4CZuRiaM45MZqBgIRbs9AqTcuFLE7VHLOh7KB5ERdjJaEaU4ClO/lgKWjKKcMiJQ8KgumcieVdQMD8cbBeuAkkC6LYLhOxoQ2PF5Ys9PKPBMen17f0CCg4VSh32JV4t8jSNqEIOEgJKPlkYBlJWRInKdiJdkmQlvKAsLBxdABA4RsbIMBggtEhcQsLKxDBC2TAS6vLENdJLDxMZAubu8vjIbzcQRtMzJz79S08oQEt/guNiyy7fcvMbh4OezdAvGrakLAQwyABsELQkY9BP+//ckyPDD4J9BfAMh1GsBoImMeQUN+lMgUJ9CiRMa5msxoB9Gh/o8GmxYMZXIgxtR/yQ46S/gQAURR0pDwYDfywoyLPip5AdnCwsMFPBU4BPFhKBDi444quCmDKZOfwZ9KEGpCKgcN1jdALSpPqIYsabS+nSqvqplvYqQYAeDPgwKwjaMtiDl0oaqUAyo+3TuWwUAMPpVCfee0cEjVBGQq2ABx7oTWmQk4FglZMGN9fGVDMCuiH2AOVOu/PmyxM630gwM0CCn6q8LjVJ8GXvpa5Uwn95OTC/nNxkda1/dLSK475IjCD6dHbK1ZOa4hXP9DXs5chJ00UpVm5xo2qRpoxptwF2E4/IbJpB/SDz9+q9b1aNfQH08+p4a8uvX8B53fLP+ycAfemjsRUBgp1H20K+BghHgVgt1GXZXZpZ5lt4ECjxYR4ScUWiShEtZqBiIInRGWnERNnjiBglw+JyGnxUmGowsyiiZg189lNtPGACjV2+S9UjbU0JWF6SPvEk3QZEqsZYTk3UAaRSUnznJI5LmESCdBVSyaOWUWLK4I5gDUYVeV1T9l+FZClCAUVA09uSmRHBCKAECFEhW51ht6rnmWBXkaR+NjuHpJ40D3DmnQXt2F+ihZxlqVKOfQRACACH5BAUKABwALAcABADOAAsAAAX/ICdyUCkUo/g8mUG8MCGkKgspeC6j6XEIEBpBUeCNfECaglBcOVfJFK7YQwZHQ6JRZBUqTrSuVEuD3nI45pYjFuWKvjjSkCoRaBUMWxkwBGgJCXspQ36Bh4EEB0oKhoiBgyNLjo8Ki4QElIiWfJqHnISNEI+Ql5J9o6SgkqKkgqYihamPkW6oNBgSfiMMDQkGCBLCwxIQDhHIyQwQCGMKxsnKVyPCF9DREQ3MxMPX0cu4wt7J2uHWx9jlKd3o39MiuefYEcvNkuLt5O8c1ePI2tyELXGQwoGDAQf+iEC2xByDCRAjTlAgIUWCBRgCPJQ4AQBFXAs0coT40WLIjRxL/47AcHLkxIomRXL0CHPERZkpa4q4iVKiyp0tR/7kwHMkTUBBJR5dOCEBAVcKKtCAyOHpowXCpk7goABqBZdcvWploACpBKkpIJI1q5OD2rIWE0R1uTZu1LFwbWL9OlKuWb4c6+o9i3dEgw0RCGDUG9KlRw56gDY2qmCByZBaASi+TACA0TucAaTteCcy0ZuOK3N2vJlx58+LRQyY3Xm0ZsgjZg+oPQLi7dUcNXi0LOJw1pgNtB7XG6CBy+U75SYfPTSQAgZTNUDnQHt67wnbZyvwLgKiMN3oCZB3C76tdewpLFgIP2C88rbi4Y+QT3+8S5USMICZXWj1pkEDeUU3lOYGB3alSoEiMIjgX4WlgNF2EibIwQIXauWXSRg2SAOHIU5IIIMoZkhhWiJaiFVbKo6AQEgQXrTAazO1JhkBrBG3Y2Y6EsUhaGn95hprSN0oWpFE7rhkeaQBchGOEWnwEmc0uKWZj0LeuNV3W4Y2lZHFlQCSRjTIl8uZ+kG5HU/3sRlnTG2ytyadytnD3HrmuRcSn+0h1dycexIK1KCjYaCnjCCVqOFFJTZ5GkUUjESWaUIKU2lgCmAKKQIUjHapXRKE+t2og1VgankNYnohqKJ2CmKplso6GKz7WYCgqxeuyoF8u9IQAgA7',
23343			msg: null,
23344			msgText: '<em>Loading the next set of posts...</em>',
23345			selector: null,
23346			speed: 'fast',
23347			start: undefined
23348		},
23349		state: {
23350			isDuringAjax: false,
23351			isInvalidPage: false,
23352			isDestroyed: false,
23353			isDone: false, // For when it goes all the way through the archive.
23354			isPaused: false,
23355			isBeyondMaxPage: false,
23356			currPage: 1
23357		},
23358		debug: false,
23359		behavior: undefined,
23360		binder: $(window), // used to cache the selector
23361		nextSelector: 'div.navigation a:first',
23362		navSelector: 'div.navigation',
23363		contentSelector: null, // rename to pageFragment
23364		extraScrollPx: 150,
23365		itemSelector: 'div.post',
23366		animate: false,
23367		pathParse: undefined,
23368		dataType: 'html',
23369		appendCallback: true,
23370		bufferPx: 40,
23371		errorCallback: function () { },
23372		infid: 0, //Instance ID
23373		pixelsFromNavToBottom: undefined,
23374		path: undefined, // Either parts of a URL as an array (e.g. ["/page/", "/"] or a function that takes in the page number and returns a URL
23375		prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted
23376		maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work)
23377	};
23378
23379	$.infinitescroll.prototype = {
23380
23381		/*
23382			----------------------------
23383			Private methods
23384			----------------------------
23385			*/
23386
23387		// Bind or unbind from scroll
23388		_binding: function infscr_binding(binding) {
23389
23390			var instance = this,
23391				opts = instance.options;
23392
23393			opts.v = '2.0b2.120520';
23394
23395			// if behavior is defined and this function is extended, call that instead of default
23396			if (!!opts.behavior && this['_binding_' + opts.behavior] !== undefined) {
23397				this['_binding_' + opts.behavior].call(this);
23398				return;
23399			}
23400
23401			if (binding !== 'bind' && binding !== 'unbind') {
23402				this._debug('Binding value  ' + binding + ' not valid');
23403				return false;
23404			}
23405
23406			if (binding === 'unbind') {
23407				(this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid);
23408			} else {
23409				(this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () {
23410					instance.scroll();
23411				});
23412			}
23413
23414			this._debug('Binding', binding);
23415		},
23416
23417		// Fundamental aspects of the plugin are initialized
23418		_create: function infscr_create(options, callback) {
23419
23420			// Add custom options to defaults
23421			var opts = $.extend(true, {}, $.infinitescroll.defaults, options);
23422			this.options = opts;
23423			var $window = $(window);
23424			var instance = this;
23425
23426			// Validate selectors
23427			if (!instance._validate(options)) {
23428				return false;
23429			}
23430
23431			// Validate page fragment path
23432			var path = $(opts.nextSelector).attr('href');
23433			if (!path) {
23434				this._debug('Navigation selector not found');
23435				return false;
23436			}
23437
23438			// Set the path to be a relative URL from root.
23439			opts.path = opts.path || this._determinepath(path);
23440
23441			// contentSelector is 'page fragment' option for .load() / .ajax() calls
23442			opts.contentSelector = opts.contentSelector || this.element;
23443
23444			// loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector
23445			opts.loading.selector = opts.loading.selector || opts.contentSelector;
23446
23447			// Define loading.msg
23448			opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>');
23449
23450			// Preload loading.img
23451			(new Image()).src = opts.loading.img;
23452
23453			// distance from nav links to bottom
23454			// computed as: height of the document + top offset of container - top offset of nav link
23455			if (opts.pixelsFromNavToBottom === undefined) {
23456				opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top;
23457				this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom);
23458			}
23459
23460			var self = this;
23461
23462			// determine loading.start actions
23463			opts.loading.start = opts.loading.start || function () {
23464				$(opts.navSelector).hide();
23465				opts.loading.msg
23466					.appendTo(opts.loading.selector)
23467					.show(opts.loading.speed, $.proxy(function () {
23468						this.beginAjax(opts);
23469					}, self));
23470			};
23471
23472			// determine loading.finished actions
23473			opts.loading.finished = opts.loading.finished || function () {
23474				if (!opts.state.isBeyondMaxPage)
23475					opts.loading.msg.fadeOut(opts.loading.speed);
23476			};
23477
23478			// callback loading
23479			opts.callback = function (instance, data, url) {
23480				if (!!opts.behavior && instance['_callback_' + opts.behavior] !== undefined) {
23481					instance['_callback_' + opts.behavior].call($(opts.contentSelector)[0], data, url);
23482				}
23483
23484				if (callback) {
23485					callback.call($(opts.contentSelector)[0], data, opts, url);
23486				}
23487
23488				if (opts.prefill) {
23489					$window.bind('resize.infinite-scroll', instance._prefill);
23490				}
23491			};
23492
23493			if (options.debug) {
23494				// Tell IE9 to use its built-in console
23495				if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') {
23496					['log', 'info', 'warn', 'error', 'assert', 'dir', 'clear', 'profile', 'profileEnd']
23497						.forEach(function (method) {
23498							console[method] = this.call(console[method], console);
23499						}, Function.prototype.bind);
23500				}
23501			}
23502
23503			this._setup();
23504
23505			// Setups the prefill method for use
23506			if (opts.prefill) {
23507				this._prefill();
23508			}
23509
23510			// Return true to indicate successful creation
23511			return true;
23512		},
23513
23514		_prefill: function infscr_prefill() {
23515			var instance = this;
23516			var $window = $(window);
23517
23518			function needsPrefill() {
23519				return ($(instance.options.contentSelector).height() <= $window.height());
23520			}
23521
23522			this._prefill = function () {
23523				if (needsPrefill()) {
23524					instance.scroll();
23525				}
23526
23527				$window.bind('resize.infinite-scroll', function () {
23528					if (needsPrefill()) {
23529						$window.unbind('resize.infinite-scroll');
23530						instance.scroll();
23531					}
23532				});
23533			};
23534
23535			// Call self after setting up the new function
23536			this._prefill();
23537		},
23538
23539		// Console log wrapper
23540		_debug: function infscr_debug() {
23541			if (true !== this.options.debug) {
23542				return;
23543			}
23544
23545			if (typeof console !== 'undefined' && typeof console.log === 'function') {
23546				// Modern browsers
23547				// Single argument, which is a string
23548				if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') {
23549					console.log((Array.prototype.slice.call(arguments)).toString());
23550				} else {
23551					console.log(Array.prototype.slice.call(arguments));
23552				}
23553			} else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') {
23554				// IE8
23555				Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));
23556			}
23557		},
23558
23559		// find the number to increment in the path.
23560		_determinepath: function infscr_determinepath(path) {
23561
23562			var opts = this.options;
23563
23564			// if behavior is defined and this function is extended, call that instead of default
23565			if (!!opts.behavior && this['_determinepath_' + opts.behavior] !== undefined) {
23566				return this['_determinepath_' + opts.behavior].call(this, path);
23567			}
23568
23569			var url = new URL(path);
23570			var pathname = url.pathname;
23571			var hasNumber = /\d/.test(pathname);
23572
23573			if (!!opts.pathParse) {
23574				this._debug('pathParse manual');
23575				return opts.pathParse(path, this.options.state.currPage + 1);
23576            } else if (hasNumber && path.match(/(\?|\&)(upage=)(\d+)/)) {
23577				var parts = path.split(/(\?|\&)(upage=)(\d+)/);
23578				return [parts[0] + parts[1] + parts[2], parts[4]];
23579            } else if (path.match(/^(.*?)\b2\b(.*?$)/)) {
23580				path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
23581
23582                // if there is any 2 in the url at all.
23583            } else if (path.match(/^(.*?)2(.*?$)/)) {
23584                // page= is used in django:
23585                // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127
23586                if (path.match(/^(.*?page=)2(\/.*|$)/)) {
23587                    path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1);
23588                    return path;
23589                }
23590
23591                path = path.match(/^(.*?)2(.*?$)/).slice(1);
23592
23593            } else {
23594                // page= is used in drupal too but second page is page=1 not page=2:
23595                // thx Jerod Fritz, vladikoff
23596                if (path.match(/^(.*?page=)1(\/.*|$)/)) {
23597                    path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1);
23598                    return path;
23599                } else {
23600                    this._debug("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.");
23601                    // Get rid of isInvalidPage to allow permalink to state
23602                    opts.state.isInvalidPage = true;  //prevent it from running on this page.
23603                }
23604            }
23605            this._debug('determinePath', path);
23606            return path;
23607
23608        },
23609
23610        // Custom error
23611        _error: function infscr_error(xhr) {
23612
23613            var opts = this.options;
23614
23615            // if behavior is defined and this function is extended, call that instead of default
23616            if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) {
23617                this['_error_'+opts.behavior].call(this,xhr);
23618                return;
23619            }
23620
23621            if (xhr !== 'destroy' && xhr !== 'end') {
23622                xhr = 'unknown';
23623            }
23624
23625            this._debug('Error', xhr);
23626
23627            if (xhr === 'end' || opts.state.isBeyondMaxPage) {
23628                this._showdonemsg();
23629            }
23630
23631            opts.state.isDone = true;
23632            opts.state.currPage = 1; // if you need to go back to this instance
23633            opts.state.isPaused = false;
23634            opts.state.isBeyondMaxPage = false;
23635            this._binding('unbind');
23636
23637        },
23638
23639        // Load Callback
23640        _loadcallback: function infscr_loadcallback(box, data, url) {
23641            var opts = this.options,
23642            callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK
23643            result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append',
23644            frag;
23645
23646            // if behavior is defined and this function is extended, call that instead of default
23647            if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) {
23648                this['_loadcallback_'+opts.behavior].call(this,box,data);
23649                return;
23650            }
23651
23652            switch (result) {
23653                case 'done':
23654                    this._showdonemsg();
23655                    return false;
23656
23657                case 'no-append':
23658                    if (opts.dataType === 'html') {
23659                        data = '<div>' + data + '</div>';
23660                        data = $(data).find(opts.itemSelector);
23661                    }
23662
23663                    // if it didn't return anything
23664                    if (data.length === 0) {
23665                        return this._error('end');
23666                    }
23667
23668                    break;
23669
23670                case 'append':
23671                    var children = box.children();
23672                    // if it didn't return anything
23673                    if (children.length === 0) {
23674                        return this._error('end');
23675                    }
23676
23677                    // use a documentFragment because it works when content is going into a table or UL
23678                    frag = document.createDocumentFragment();
23679                    while (box[0].firstChild) {
23680                        frag.appendChild(box[0].firstChild);
23681                    }
23682
23683                    this._debug('contentSelector', $(opts.contentSelector)[0]);
23684                    $(opts.contentSelector)[0].appendChild(frag);
23685                    // previously, we would pass in the new DOM element as context for the callback
23686                    // however we're now using a documentfragment, which doesn't have parents or children,
23687                    // so the context is the contentContainer guy, and we pass in an array
23688                    // of the elements collected as the first argument.
23689
23690                    data = children.get();
23691                    break;
23692            }
23693
23694            // loadingEnd function
23695            opts.loading.finished.call($(opts.contentSelector)[0],opts);
23696
23697            // smooth scroll to ease in the new content
23698            if (opts.animate) {
23699                var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px';
23700                $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; });
23701            }
23702
23703            if (!opts.animate) {
23704                // once the call is done, we can allow it again.
23705                opts.state.isDuringAjax = false;
23706            }
23707
23708            callback(this, data, url);
23709
23710            if (opts.prefill) {
23711                this._prefill();
23712            }
23713        },
23714
23715        _nearbottom: function infscr_nearbottom() {
23716
23717            var opts = this.options,
23718            pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height();
23719
23720            // if behavior is defined and this function is extended, call that instead of default
23721            if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) {
23722                return this['_nearbottom_'+opts.behavior].call(this);
23723            }
23724
23725            this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom);
23726
23727            // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
23728            return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom);
23729
23730        },
23731
23732        // Pause / temporarily disable plugin from firing
23733        _pausing: function infscr_pausing(pause) {
23734
23735            var opts = this.options;
23736
23737            // if behavior is defined and this function is extended, call that instead of default
23738            if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) {
23739                this['_pausing_'+opts.behavior].call(this,pause);
23740                return;
23741            }
23742
23743            // If pause is not 'pause' or 'resume', toggle it's value
23744            if (pause !== 'pause' && pause !== 'resume' && pause !== null) {
23745                this._debug('Invalid argument. Toggling pause value instead');
23746            }
23747
23748            pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle';
23749
23750            switch (pause) {
23751                case 'pause':
23752                    opts.state.isPaused = true;
23753                break;
23754
23755                case 'resume':
23756                    opts.state.isPaused = false;
23757                break;
23758
23759                case 'toggle':
23760                    opts.state.isPaused = !opts.state.isPaused;
23761                break;
23762            }
23763
23764            this._debug('Paused', opts.state.isPaused);
23765            return false;
23766
23767        },
23768
23769        // Behavior is determined
23770        // If the behavior option is undefined, it will set to default and bind to scroll
23771        _setup: function infscr_setup() {
23772
23773            var opts = this.options;
23774
23775            // if behavior is defined and this function is extended, call that instead of default
23776            if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) {
23777                this['_setup_'+opts.behavior].call(this);
23778                return;
23779            }
23780
23781            this._binding('bind');
23782
23783            return false;
23784
23785        },
23786
23787        // Show done message
23788        _showdonemsg: function infscr_showdonemsg() {
23789
23790            var opts = this.options;
23791
23792            // if behavior is defined and this function is extended, call that instead of default
23793            if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) {
23794                this['_showdonemsg_'+opts.behavior].call(this);
23795                return;
23796            }
23797
23798            opts.loading.msg
23799            .find('img')
23800            .hide()
23801            .parent()
23802            .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () {
23803                $(this).parent().fadeOut(opts.loading.speed);
23804            });
23805
23806            // user provided callback when done
23807            opts.errorCallback.call($(opts.contentSelector)[0],'done');
23808        },
23809
23810        // grab each selector option and see if any fail
23811        _validate: function infscr_validate(opts) {
23812            for (var key in opts) {
23813                if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) {
23814                    this._debug('Your ' + key + ' found no elements.');
23815                    return false;
23816                }
23817            }
23818
23819            return true;
23820        },
23821
23822        /*
23823            ----------------------------
23824            Public methods
23825            ----------------------------
23826            */
23827
23828        // Bind to scroll
23829        bind: function infscr_bind() {
23830            this._binding('bind');
23831        },
23832
23833        // Destroy current instance of plugin
23834        destroy: function infscr_destroy() {
23835            this.options.state.isDestroyed = true;
23836            this.options.loading.finished();
23837            return this._error('destroy');
23838        },
23839
23840        // Set pause value to false
23841        pause: function infscr_pause() {
23842            this._pausing('pause');
23843        },
23844
23845        // Set pause value to false
23846        resume: function infscr_resume() {
23847            this._pausing('resume');
23848        },
23849
23850        beginAjax: function infscr_ajax(opts) {
23851            var instance = this,
23852                path = opts.path,
23853                box, desturl, method, condition;
23854
23855			// increment the URL bit. e.g. /page/3/
23856            opts.state.currPage++;
23857
23858            // Manually control maximum page
23859            if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){
23860                opts.state.isBeyondMaxPage = true;
23861                this.destroy();
23862                return;
23863            }
23864
23865            // if we're dealing with a table we can't use DIVs
23866            box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>');
23867
23868			desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage);
23869
23870            instance._debug('heading into ajax', desturl);
23871
23872            method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback';
23873            if (opts.appendCallback && opts.dataType === 'html') {
23874                method += '+callback';
23875            }
23876
23877            switch (method) {
23878                case 'html+callback':
23879                    instance._debug('Using HTML via .load() method');
23880                    box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) {
23881                        instance._loadcallback(box, responseText, desturl);
23882                    });
23883
23884                    break;
23885
23886                case 'html':
23887                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
23888                    $.ajax({
23889                        // params
23890                        url: desturl,
23891                        dataType: opts.dataType,
23892                        complete: function infscr_ajax_callback(jqXHR, textStatus) {
23893                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
23894                            if (condition) {
23895                                instance._loadcallback(box, jqXHR.responseText, desturl);
23896                            } else {
23897                                instance._error('end');
23898                            }
23899                        }
23900                    });
23901
23902                    break;
23903                case 'json':
23904                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
23905                    $.ajax({
23906                        dataType: 'json',
23907                        type: 'GET',
23908                        url: desturl,
23909                        success: function (data, textStatus, jqXHR) {
23910                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
23911                            if (opts.appendCallback) {
23912                                // if appendCallback is true, you must defined template in options.
23913                                // note that data passed into _loadcallback is already an html (after processed in opts.template(data)).
23914                                if (opts.template !== undefined) {
23915                                    var theData = opts.template(data);
23916                                    box.append(theData);
23917                                    if (condition) {
23918                                        instance._loadcallback(box, theData);
23919                                    } else {
23920                                        instance._error('end');
23921                                    }
23922                                } else {
23923                                    instance._debug('template must be defined.');
23924                                    instance._error('end');
23925                                }
23926                            } else {
23927                                // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback.
23928                                if (condition) {
23929                                    instance._loadcallback(box, data, desturl);
23930                                } else {
23931                                    instance._error('end');
23932                                }
23933                            }
23934                        },
23935                        error: function() {
23936                            instance._debug('JSON ajax request failed.');
23937                            instance._error('end');
23938                        }
23939                    });
23940
23941                    break;
23942            }
23943        },
23944
23945        // Retrieve next set of content items
23946        retrieve: function infscr_retrieve(pageNum) {
23947            pageNum = pageNum || null;
23948
23949            var instance = this,
23950            opts = instance.options;
23951
23952            // if behavior is defined and this function is extended, call that instead of default
23953            if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) {
23954                this['retrieve_'+opts.behavior].call(this,pageNum);
23955                return;
23956            }
23957
23958            // for manual triggers, if destroyed, get out of here
23959            if (opts.state.isDestroyed) {
23960                this._debug('Instance is destroyed');
23961                return false;
23962            }
23963
23964            // we dont want to fire the ajax multiple times
23965            opts.state.isDuringAjax = true;
23966
23967            opts.loading.start.call($(opts.contentSelector)[0],opts);
23968        },
23969
23970        // Check to see next page is needed
23971        scroll: function infscr_scroll() {
23972
23973            var opts = this.options,
23974            state = opts.state;
23975
23976            // if behavior is defined and this function is extended, call that instead of default
23977            if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) {
23978                this['scroll_'+opts.behavior].call(this);
23979                return;
23980            }
23981
23982            if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) {
23983                return;
23984            }
23985
23986            if (!this._nearbottom()) {
23987                return;
23988            }
23989
23990            this.retrieve();
23991
23992        },
23993
23994        // Toggle pause value
23995        toggle: function infscr_toggle() {
23996            this._pausing();
23997        },
23998
23999        // Unbind from scroll
24000        unbind: function infscr_unbind() {
24001            this._binding('unbind');
24002        },
24003
24004        // update options
24005        update: function infscr_options(key) {
24006            if ($.isPlainObject(key)) {
24007                this.options = $.extend(true,this.options,key);
24008            }
24009        }
24010    };
24011
24012
24013    /*
24014        ----------------------------
24015        Infinite Scroll function
24016        ----------------------------
24017
24018        Borrowed logic from the following...
24019
24020        jQuery UI
24021        - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
24022
24023        jCarousel
24024        - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
24025
24026        Masonry
24027        - https://github.com/desandro/masonry/blob/master/jquery.masonry.js
24028
24029*/
24030
24031    $.fn.infinitescroll = function infscr_init(options, callback) {
24032
24033
24034        var thisCall = typeof options;
24035
24036        switch (thisCall) {
24037
24038            // method
24039            case 'string':
24040                var args = Array.prototype.slice.call(arguments, 1);
24041
24042                this.each(function () {
24043                    var instance = $.data(this, 'infinitescroll');
24044
24045                    if (!instance) {
24046                        // not setup yet
24047                        // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup');
24048                        return false;
24049                    }
24050
24051                    if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
24052                        // return $.error('No such method ' + options + ' for Infinite Scroll');
24053                        return false;
24054                    }
24055
24056                    // no errors!
24057                    instance[options].apply(instance, args);
24058                });
24059
24060            break;
24061
24062            // creation
24063            case 'object':
24064
24065                this.each(function () {
24066
24067                var instance = $.data(this, 'infinitescroll');
24068
24069                if (instance) {
24070
24071                    // update options of current instance
24072                    instance.update(options);
24073
24074                } else {
24075
24076                    // initialize new instance
24077                    instance = new $.infinitescroll(options, callback, this);
24078
24079                    // don't attach if instantiation failed
24080                    if (!instance.failed) {
24081                        $.data(this, 'infinitescroll', instance);
24082                    }
24083
24084                }
24085
24086            });
24087
24088            break;
24089
24090        }
24091
24092        return this;
24093    };
24094
24095
24096
24097    /*
24098     * smartscroll: debounced scroll event for jQuery *
24099     * https://github.com/lukeshumard/smartscroll
24100     * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js *
24101     * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. *
24102     */
24103
24104    var event = $.event,
24105    scrollTimeout;
24106
24107    event.special.smartscroll = {
24108        setup: function () {
24109            $(this).bind('scroll', event.special.smartscroll.handler);
24110        },
24111        teardown: function () {
24112            $(this).unbind('scroll', event.special.smartscroll.handler);
24113        },
24114        handler: function (event, execAsap) {
24115            // Save the context
24116            var context = this,
24117            args = arguments;
24118
24119            // set correct event type
24120            event.type = 'smartscroll';
24121
24122            if (scrollTimeout) { clearTimeout(scrollTimeout); }
24123            scrollTimeout = setTimeout(function () {
24124                $(context).trigger('smartscroll', args);
24125            }, execAsap === 'execAsap' ? 0 : 100);
24126        }
24127    };
24128
24129    $.fn.smartscroll = function (fn) {
24130        return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']);
24131    };
24132
24133}));
24134
24135/*!
24136Waypoints - 4.0.1
24137Copyright © 2011-2016 Caleb Troughton
24138Licensed under the MIT license.
24139https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
24140*/
24141(function() {
24142  'use strict'
24143
24144  var keyCounter = 0
24145  var allWaypoints = {}
24146
24147  /* http://imakewebthings.com/waypoints/api/waypoint */
24148  function Waypoint(options) {
24149    if (!options) {
24150      throw new Error('No options passed to Waypoint constructor')
24151    }
24152    if (!options.element) {
24153      throw new Error('No element option passed to Waypoint constructor')
24154    }
24155    if (!options.handler) {
24156      throw new Error('No handler option passed to Waypoint constructor')
24157    }
24158
24159    this.key = 'waypoint-' + keyCounter
24160    this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
24161    this.element = this.options.element
24162    this.adapter = new Waypoint.Adapter(this.element)
24163    this.callback = options.handler
24164    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
24165    this.enabled = this.options.enabled
24166    this.triggerPoint = null
24167    this.group = Waypoint.Group.findOrCreate({
24168      name: this.options.group,
24169      axis: this.axis
24170    })
24171    this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
24172
24173    if (Waypoint.offsetAliases[this.options.offset]) {
24174      this.options.offset = Waypoint.offsetAliases[this.options.offset]
24175    }
24176    this.group.add(this)
24177    this.context.add(this)
24178    allWaypoints[this.key] = this
24179    keyCounter += 1
24180  }
24181
24182  /* Private */
24183  Waypoint.prototype.queueTrigger = function(direction) {
24184    this.group.queueTrigger(this, direction)
24185  }
24186
24187  /* Private */
24188  Waypoint.prototype.trigger = function(args) {
24189    if (!this.enabled) {
24190      return
24191    }
24192    if (this.callback) {
24193      this.callback.apply(this, args)
24194    }
24195  }
24196
24197  /* Public */
24198  /* http://imakewebthings.com/waypoints/api/destroy */
24199  Waypoint.prototype.destroy = function() {
24200    this.context.remove(this)
24201    this.group.remove(this)
24202    delete allWaypoints[this.key]
24203  }
24204
24205  /* Public */
24206  /* http://imakewebthings.com/waypoints/api/disable */
24207  Waypoint.prototype.disable = function() {
24208    this.enabled = false
24209    return this
24210  }
24211
24212  /* Public */
24213  /* http://imakewebthings.com/waypoints/api/enable */
24214  Waypoint.prototype.enable = function() {
24215    this.context.refresh()
24216    this.enabled = true
24217    return this
24218  }
24219
24220  /* Public */
24221  /* http://imakewebthings.com/waypoints/api/next */
24222  Waypoint.prototype.next = function() {
24223    return this.group.next(this)
24224  }
24225
24226  /* Public */
24227  /* http://imakewebthings.com/waypoints/api/previous */
24228  Waypoint.prototype.previous = function() {
24229    return this.group.previous(this)
24230  }
24231
24232  /* Private */
24233  Waypoint.invokeAll = function(method) {
24234    var allWaypointsArray = []
24235    for (var waypointKey in allWaypoints) {
24236      allWaypointsArray.push(allWaypoints[waypointKey])
24237    }
24238    for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
24239      allWaypointsArray[i][method]()
24240    }
24241  }
24242
24243  /* Public */
24244  /* http://imakewebthings.com/waypoints/api/destroy-all */
24245  Waypoint.destroyAll = function() {
24246    Waypoint.invokeAll('destroy')
24247  }
24248
24249  /* Public */
24250  /* http://imakewebthings.com/waypoints/api/disable-all */
24251  Waypoint.disableAll = function() {
24252    Waypoint.invokeAll('disable')
24253  }
24254
24255  /* Public */
24256  /* http://imakewebthings.com/waypoints/api/enable-all */
24257  Waypoint.enableAll = function() {
24258    Waypoint.Context.refreshAll()
24259    for (var waypointKey in allWaypoints) {
24260      allWaypoints[waypointKey].enabled = true
24261    }
24262    return this
24263  }
24264
24265  /* Public */
24266  /* http://imakewebthings.com/waypoints/api/refresh-all */
24267  Waypoint.refreshAll = function() {
24268    Waypoint.Context.refreshAll()
24269  }
24270
24271  /* Public */
24272  /* http://imakewebthings.com/waypoints/api/viewport-height */
24273  Waypoint.viewportHeight = function() {
24274    return window.innerHeight || document.documentElement.clientHeight
24275  }
24276
24277  /* Public */
24278  /* http://imakewebthings.com/waypoints/api/viewport-width */
24279  Waypoint.viewportWidth = function() {
24280    return document.documentElement.clientWidth
24281  }
24282
24283  Waypoint.adapters = []
24284
24285  Waypoint.defaults = {
24286    context: window,
24287    continuous: true,
24288    enabled: true,
24289    group: 'default',
24290    horizontal: false,
24291    offset: 0
24292  }
24293
24294  Waypoint.offsetAliases = {
24295    'bottom-in-view': function() {
24296      return this.context.innerHeight() - this.adapter.outerHeight()
24297    },
24298    'right-in-view': function() {
24299      return this.context.innerWidth() - this.adapter.outerWidth()
24300    }
24301  }
24302
24303  window.Waypoint = Waypoint
24304}())
24305;(function() {
24306  'use strict'
24307
24308  function requestAnimationFrameShim(callback) {
24309    window.setTimeout(callback, 1000 / 60)
24310  }
24311
24312  var keyCounter = 0
24313  var contexts = {}
24314  var Waypoint = window.Waypoint
24315  var oldWindowLoad = window.onload
24316
24317  /* http://imakewebthings.com/waypoints/api/context */
24318  function Context(element) {
24319    this.element = element
24320    this.Adapter = Waypoint.Adapter
24321    this.adapter = new this.Adapter(element)
24322    this.key = 'waypoint-context-' + keyCounter
24323    this.didScroll = false
24324    this.didResize = false
24325    this.oldScroll = {
24326      x: this.adapter.scrollLeft(),
24327      y: this.adapter.scrollTop()
24328    }
24329    this.waypoints = {
24330      vertical: {},
24331      horizontal: {}
24332    }
24333
24334    element.waypointContextKey = this.key
24335    contexts[element.waypointContextKey] = this
24336    keyCounter += 1
24337    if (!Waypoint.windowContext) {
24338      Waypoint.windowContext = true
24339      Waypoint.windowContext = new Context(window)
24340    }
24341
24342    this.createThrottledScrollHandler()
24343    this.createThrottledResizeHandler()
24344  }
24345
24346  /* Private */
24347  Context.prototype.add = function(waypoint) {
24348    var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
24349    this.waypoints[axis][waypoint.key] = waypoint
24350    this.refresh()
24351  }
24352
24353  /* Private */
24354  Context.prototype.checkEmpty = function() {
24355    var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
24356    var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
24357    var isWindow = this.element == this.element.window
24358    if (horizontalEmpty && verticalEmpty && !isWindow) {
24359      this.adapter.off('.waypoints')
24360      delete contexts[this.key]
24361    }
24362  }
24363
24364  /* Private */
24365  Context.prototype.createThrottledResizeHandler = function() {
24366    var self = this
24367
24368    function resizeHandler() {
24369      self.handleResize()
24370      self.didResize = false
24371    }
24372
24373    this.adapter.on('resize.waypoints', function() {
24374      if (!self.didResize) {
24375        self.didResize = true
24376        Waypoint.requestAnimationFrame(resizeHandler)
24377      }
24378    })
24379  }
24380
24381  /* Private */
24382  Context.prototype.createThrottledScrollHandler = function() {
24383    var self = this
24384    function scrollHandler() {
24385      self.handleScroll()
24386      self.didScroll = false
24387    }
24388
24389    this.adapter.on('scroll.waypoints', function() {
24390      if (!self.didScroll || Waypoint.isTouch) {
24391        self.didScroll = true
24392        Waypoint.requestAnimationFrame(scrollHandler)
24393      }
24394    })
24395  }
24396
24397  /* Private */
24398  Context.prototype.handleResize = function() {
24399    Waypoint.Context.refreshAll()
24400  }
24401
24402  /* Private */
24403  Context.prototype.handleScroll = function() {
24404    var triggeredGroups = {}
24405    var axes = {
24406      horizontal: {
24407        newScroll: this.adapter.scrollLeft(),
24408        oldScroll: this.oldScroll.x,
24409        forward: 'right',
24410        backward: 'left'
24411      },
24412      vertical: {
24413        newScroll: this.adapter.scrollTop(),
24414        oldScroll: this.oldScroll.y,
24415        forward: 'down',
24416        backward: 'up'
24417      }
24418    }
24419
24420    for (var axisKey in axes) {
24421      var axis = axes[axisKey]
24422      var isForward = axis.newScroll > axis.oldScroll
24423      var direction = isForward ? axis.forward : axis.backward
24424
24425      for (var waypointKey in this.waypoints[axisKey]) {
24426        var waypoint = this.waypoints[axisKey][waypointKey]
24427        if (waypoint.triggerPoint === null) {
24428          continue
24429        }
24430        var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
24431        var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
24432        var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
24433        var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
24434        if (crossedForward || crossedBackward) {
24435          waypoint.queueTrigger(direction)
24436          triggeredGroups[waypoint.group.id] = waypoint.group
24437        }
24438      }
24439    }
24440
24441    for (var groupKey in triggeredGroups) {
24442      triggeredGroups[groupKey].flushTriggers()
24443    }
24444
24445    this.oldScroll = {
24446      x: axes.horizontal.newScroll,
24447      y: axes.vertical.newScroll
24448    }
24449  }
24450
24451  /* Private */
24452  Context.prototype.innerHeight = function() {
24453    /*eslint-disable eqeqeq */
24454    if (this.element == this.element.window) {
24455      return Waypoint.viewportHeight()
24456    }
24457    /*eslint-enable eqeqeq */
24458    return this.adapter.innerHeight()
24459  }
24460
24461  /* Private */
24462  Context.prototype.remove = function(waypoint) {
24463    delete this.waypoints[waypoint.axis][waypoint.key]
24464    this.checkEmpty()
24465  }
24466
24467  /* Private */
24468  Context.prototype.innerWidth = function() {
24469    /*eslint-disable eqeqeq */
24470    if (this.element == this.element.window) {
24471      return Waypoint.viewportWidth()
24472    }
24473    /*eslint-enable eqeqeq */
24474    return this.adapter.innerWidth()
24475  }
24476
24477  /* Public */
24478  /* http://imakewebthings.com/waypoints/api/context-destroy */
24479  Context.prototype.destroy = function() {
24480    var allWaypoints = []
24481    for (var axis in this.waypoints) {
24482      for (var waypointKey in this.waypoints[axis]) {
24483        allWaypoints.push(this.waypoints[axis][waypointKey])
24484      }
24485    }
24486    for (var i = 0, end = allWaypoints.length; i < end; i++) {
24487      allWaypoints[i].destroy()
24488    }
24489  }
24490
24491  /* Public */
24492  /* http://imakewebthings.com/waypoints/api/context-refresh */
24493  Context.prototype.refresh = function() {
24494    /*eslint-disable eqeqeq */
24495    var isWindow = this.element == this.element.window
24496    /*eslint-enable eqeqeq */
24497    var contextOffset = isWindow ? undefined : this.adapter.offset()
24498    var triggeredGroups = {}
24499    var axes
24500
24501    this.handleScroll()
24502    axes = {
24503      horizontal: {
24504        contextOffset: isWindow ? 0 : contextOffset.left,
24505        contextScroll: isWindow ? 0 : this.oldScroll.x,
24506        contextDimension: this.innerWidth(),
24507        oldScroll: this.oldScroll.x,
24508        forward: 'right',
24509        backward: 'left',
24510        offsetProp: 'left'
24511      },
24512      vertical: {
24513        contextOffset: isWindow ? 0 : contextOffset.top,
24514        contextScroll: isWindow ? 0 : this.oldScroll.y,
24515        contextDimension: this.innerHeight(),
24516        oldScroll: this.oldScroll.y,
24517        forward: 'down',
24518        backward: 'up',
24519        offsetProp: 'top'
24520      }
24521    }
24522
24523    for (var axisKey in axes) {
24524      var axis = axes[axisKey]
24525      for (var waypointKey in this.waypoints[axisKey]) {
24526        var waypoint = this.waypoints[axisKey][waypointKey]
24527        var adjustment = waypoint.options.offset
24528        var oldTriggerPoint = waypoint.triggerPoint
24529        var elementOffset = 0
24530        var freshWaypoint = oldTriggerPoint == null
24531        var contextModifier, wasBeforeScroll, nowAfterScroll
24532        var triggeredBackward, triggeredForward
24533
24534        if (waypoint.element !== waypoint.element.window) {
24535          elementOffset = waypoint.adapter.offset()[axis.offsetProp]
24536        }
24537
24538        if (typeof adjustment === 'function') {
24539          adjustment = adjustment.apply(waypoint)
24540        }
24541        else if (typeof adjustment === 'string') {
24542          adjustment = parseFloat(adjustment)
24543          if (waypoint.options.offset.indexOf('%') > - 1) {
24544            adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
24545          }
24546        }
24547
24548        contextModifier = axis.contextScroll - axis.contextOffset
24549        waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
24550        wasBeforeScroll = oldTriggerPoint < axis.oldScroll
24551        nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
24552        triggeredBackward = wasBeforeScroll && nowAfterScroll
24553        triggeredForward = !wasBeforeScroll && !nowAfterScroll
24554
24555        if (!freshWaypoint && triggeredBackward) {
24556          waypoint.queueTrigger(axis.backward)
24557          triggeredGroups[waypoint.group.id] = waypoint.group
24558        }
24559        else if (!freshWaypoint && triggeredForward) {
24560          waypoint.queueTrigger(axis.forward)
24561          triggeredGroups[waypoint.group.id] = waypoint.group
24562        }
24563        else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
24564          waypoint.queueTrigger(axis.forward)
24565          triggeredGroups[waypoint.group.id] = waypoint.group
24566        }
24567      }
24568    }
24569
24570    Waypoint.requestAnimationFrame(function() {
24571      for (var groupKey in triggeredGroups) {
24572        triggeredGroups[groupKey].flushTriggers()
24573      }
24574    })
24575
24576    return this
24577  }
24578
24579  /* Private */
24580  Context.findOrCreateByElement = function(element) {
24581    return Context.findByElement(element) || new Context(element)
24582  }
24583
24584  /* Private */
24585  Context.refreshAll = function() {
24586    for (var contextId in contexts) {
24587      contexts[contextId].refresh()
24588    }
24589  }
24590
24591  /* Public */
24592  /* http://imakewebthings.com/waypoints/api/context-find-by-element */
24593  Context.findByElement = function(element) {
24594    return contexts[element.waypointContextKey]
24595  }
24596
24597  window.onload = function() {
24598    if (oldWindowLoad) {
24599      oldWindowLoad()
24600    }
24601    Context.refreshAll()
24602  }
24603
24604
24605  Waypoint.requestAnimationFrame = function(callback) {
24606    var requestFn = window.requestAnimationFrame ||
24607      window.mozRequestAnimationFrame ||
24608      window.webkitRequestAnimationFrame ||
24609      requestAnimationFrameShim
24610    requestFn.call(window, callback)
24611  }
24612  Waypoint.Context = Context
24613}())
24614;(function() {
24615  'use strict'
24616
24617  function byTriggerPoint(a, b) {
24618    return a.triggerPoint - b.triggerPoint
24619  }
24620
24621  function byReverseTriggerPoint(a, b) {
24622    return b.triggerPoint - a.triggerPoint
24623  }
24624
24625  var groups = {
24626    vertical: {},
24627    horizontal: {}
24628  }
24629  var Waypoint = window.Waypoint
24630
24631  /* http://imakewebthings.com/waypoints/api/group */
24632  function Group(options) {
24633    this.name = options.name
24634    this.axis = options.axis
24635    this.id = this.name + '-' + this.axis
24636    this.waypoints = []
24637    this.clearTriggerQueues()
24638    groups[this.axis][this.name] = this
24639  }
24640
24641  /* Private */
24642  Group.prototype.add = function(waypoint) {
24643    this.waypoints.push(waypoint)
24644  }
24645
24646  /* Private */
24647  Group.prototype.clearTriggerQueues = function() {
24648    this.triggerQueues = {
24649      up: [],
24650      down: [],
24651      left: [],
24652      right: []
24653    }
24654  }
24655
24656  /* Private */
24657  Group.prototype.flushTriggers = function() {
24658    for (var direction in this.triggerQueues) {
24659      var waypoints = this.triggerQueues[direction]
24660      var reverse = direction === 'up' || direction === 'left'
24661      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
24662      for (var i = 0, end = waypoints.length; i < end; i += 1) {
24663        var waypoint = waypoints[i]
24664        if (waypoint.options.continuous || i === waypoints.length - 1) {
24665          waypoint.trigger([direction])
24666        }
24667      }
24668    }
24669    this.clearTriggerQueues()
24670  }
24671
24672  /* Private */
24673  Group.prototype.next = function(waypoint) {
24674    this.waypoints.sort(byTriggerPoint)
24675    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
24676    var isLast = index === this.waypoints.length - 1
24677    return isLast ? null : this.waypoints[index + 1]
24678  }
24679
24680  /* Private */
24681  Group.prototype.previous = function(waypoint) {
24682    this.waypoints.sort(byTriggerPoint)
24683    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
24684    return index ? this.waypoints[index - 1] : null
24685  }
24686
24687  /* Private */
24688  Group.prototype.queueTrigger = function(waypoint, direction) {
24689    this.triggerQueues[direction].push(waypoint)
24690  }
24691
24692  /* Private */
24693  Group.prototype.remove = function(waypoint) {
24694    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
24695    if (index > -1) {
24696      this.waypoints.splice(index, 1)
24697    }
24698  }
24699
24700  /* Public */
24701  /* http://imakewebthings.com/waypoints/api/first */
24702  Group.prototype.first = function() {
24703    return this.waypoints[0]
24704  }
24705
24706  /* Public */
24707  /* http://imakewebthings.com/waypoints/api/last */
24708  Group.prototype.last = function() {
24709    return this.waypoints[this.waypoints.length - 1]
24710  }
24711
24712  /* Private */
24713  Group.findOrCreate = function(options) {
24714    return groups[options.axis][options.name] || new Group(options)
24715  }
24716
24717  Waypoint.Group = Group
24718}())
24719;(function() {
24720  'use strict'
24721
24722  var $ = window.jQuery
24723  var Waypoint = window.Waypoint
24724
24725  function JQueryAdapter(element) {
24726    this.$element = $(element)
24727  }
24728
24729  $.each([
24730    'innerHeight',
24731    'innerWidth',
24732    'off',
24733    'offset',
24734    'on',
24735    'outerHeight',
24736    'outerWidth',
24737    'scrollLeft',
24738    'scrollTop'
24739  ], function(i, method) {
24740    JQueryAdapter.prototype[method] = function() {
24741      var args = Array.prototype.slice.call(arguments)
24742      return this.$element[method].apply(this.$element, args)
24743    }
24744  })
24745
24746  $.each([
24747    'extend',
24748    'inArray',
24749    'isEmptyObject'
24750  ], function(i, method) {
24751    JQueryAdapter[method] = $[method]
24752  })
24753
24754  Waypoint.adapters.push({
24755    name: 'jquery',
24756    Adapter: JQueryAdapter
24757  })
24758  Waypoint.Adapter = JQueryAdapter
24759}())
24760;(function() {
24761  'use strict'
24762
24763  var Waypoint = window.Waypoint
24764
24765  function createExtension(framework) {
24766    return function() {
24767      var waypoints = []
24768      var overrides = arguments[0]
24769
24770      if (framework.isFunction(arguments[0])) {
24771        overrides = framework.extend({}, arguments[1])
24772        overrides.handler = arguments[0]
24773      }
24774
24775      this.each(function() {
24776        var options = framework.extend({}, overrides, {
24777          element: this
24778        })
24779        if (typeof options.context === 'string') {
24780          options.context = framework(this).closest(options.context)[0]
24781        }
24782        waypoints.push(new Waypoint(options))
24783      })
24784
24785      return waypoints
24786    }
24787  }
24788
24789  if (window.jQuery) {
24790    window.jQuery.fn.waypoint = createExtension(window.jQuery)
24791  }
24792  if (window.Zepto) {
24793    window.Zepto.fn.waypoint = createExtension(window.Zepto)
24794  }
24795}())
24796;
24797/*!
24798Waypoints Inview Shortcut - 4.0.1
24799Copyright © 2011-2016 Caleb Troughton
24800Licensed under the MIT license.
24801https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
24802*/
24803(function() {
24804  'use strict'
24805
24806  function noop() {}
24807
24808  var Waypoint = window.Waypoint
24809
24810  /* http://imakewebthings.com/waypoints/shortcuts/inview */
24811  function Inview(options) {
24812    this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
24813    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
24814    this.waypoints = []
24815    this.element = this.options.element
24816    this.createWaypoints()
24817  }
24818
24819  /* Private */
24820  Inview.prototype.createWaypoints = function() {
24821    var configs = {
24822      vertical: [{
24823        down: 'enter',
24824        up: 'exited',
24825        offset: '100%'
24826      }, {
24827        down: 'entered',
24828        up: 'exit',
24829        offset: 'bottom-in-view'
24830      }, {
24831        down: 'exit',
24832        up: 'entered',
24833        offset: 0
24834      }, {
24835        down: 'exited',
24836        up: 'enter',
24837        offset: function() {
24838          return -this.adapter.outerHeight()
24839        }
24840      }],
24841      horizontal: [{
24842        right: 'enter',
24843        left: 'exited',
24844        offset: '100%'
24845      }, {
24846        right: 'entered',
24847        left: 'exit',
24848        offset: 'right-in-view'
24849      }, {
24850        right: 'exit',
24851        left: 'entered',
24852        offset: 0
24853      }, {
24854        right: 'exited',
24855        left: 'enter',
24856        offset: function() {
24857          return -this.adapter.outerWidth()
24858        }
24859      }]
24860    }
24861
24862    for (var i = 0, end = configs[this.axis].length; i < end; i++) {
24863      var config = configs[this.axis][i]
24864      this.createWaypoint(config)
24865    }
24866  }
24867
24868  /* Private */
24869  Inview.prototype.createWaypoint = function(config) {
24870    var self = this
24871    this.waypoints.push(new Waypoint({
24872      context: this.options.context,
24873      element: this.options.element,
24874      enabled: this.options.enabled,
24875      handler: (function(config) {
24876        return function(direction) {
24877          self.options[config[direction]].call(self, direction)
24878        }
24879      }(config)),
24880      offset: config.offset,
24881      horizontal: this.options.horizontal
24882    }))
24883  }
24884
24885  /* Public */
24886  Inview.prototype.destroy = function() {
24887    for (var i = 0, end = this.waypoints.length; i < end; i++) {
24888      this.waypoints[i].destroy()
24889    }
24890    this.waypoints = []
24891  }
24892
24893  Inview.prototype.disable = function() {
24894    for (var i = 0, end = this.waypoints.length; i < end; i++) {
24895      this.waypoints[i].disable()
24896    }
24897  }
24898
24899  Inview.prototype.enable = function() {
24900    for (var i = 0, end = this.waypoints.length; i < end; i++) {
24901      this.waypoints[i].enable()
24902    }
24903  }
24904
24905  Inview.defaults = {
24906    context: window,
24907    enabled: true,
24908    enter: noop,
24909    entered: noop,
24910    exit: noop,
24911    exited: noop
24912  }
24913
24914  Waypoint.Inview = Inview
24915}())
24916;
24917
24918/*
24919 * SmartMenus jQuery v0.9.6
24920 * http://www.smartmenus.org/
24921 *
24922 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
24923 * http://vadikom.com/
24924 *
24925 * Released under the MIT license:
24926 * http://www.opensource.org/licenses/MIT
24927 */
24928
24929(function($) {
24930
24931	var menuTrees = [],
24932		IE = !!window.createPopup, // we need to detect it, unfortunately
24933		IElt9 = IE && !document.defaultView,
24934		IElt8 = IE && !document.querySelector,
24935		IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
24936		mouse = false, // optimize for touch by default - we will detect for mouse input
24937		mouseDetectionEnabled = false;
24938
24939	// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
24940	function initMouseDetection(disable) {
24941		if (!mouseDetectionEnabled && !disable) {
24942			// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
24943			// in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events)
24944			var firstTime = true,
24945				lastMove = null;
24946			$(document).bind({
24947				'mousemove.smartmenus_mouse': function(e) {
24948					var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
24949					if (lastMove) {
24950						var deltaX = Math.abs(lastMove.x - thisMove.x),
24951							deltaY = Math.abs(lastMove.y - thisMove.y);
24952	 					if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
24953							mouse = true;
24954							// if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes
24955							if (firstTime) {
24956								var $a = $(e.target).closest('a');
24957								if ($a.is('a')) {
24958									$.each(menuTrees, function() {
24959										if ($.contains(this.$root[0], $a[0])) {
24960											this.itemEnter({ currentTarget: $a[0] });
24961											return false;
24962										}
24963									});
24964								}
24965								firstTime = false;
24966							}
24967						}
24968					}
24969					lastMove = thisMove;
24970				},
24971				'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
24972					if (!/^(4|mouse|pen)$/.test(e.originalEvent.pointerType)) {
24973						mouse = false;
24974					}
24975				}
24976			});
24977			mouseDetectionEnabled = true;
24978		} else if (mouseDetectionEnabled && disable) {
24979			$(document).unbind('.smartmenus_mouse');
24980			mouseDetectionEnabled = false;
24981		}
24982	};
24983
24984	$.SmartMenus = function(elm, options) {
24985		this.$root = $(elm);
24986		this.opts = options;
24987		this.rootId = ''; // internal
24988		this.$subArrow = null;
24989		this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted)
24990		this.activatedItems = []; // stores last activated A's for each level
24991		this.visibleSubMenus = []; // stores visible sub menus UL's
24992		this.showTimeout = 0;
24993		this.hideTimeout = 0;
24994		this.scrollTimeout = 0;
24995		this.clickActivated = false;
24996		this.zIndexInc = 0;
24997		this.$firstLink = null; // we'll use these for some tests
24998		this.$firstSub = null; // at runtime so we'll cache them
24999		this.disabled = false;
25000		this.$disableOverlay = null;
25001		this.lastLevel = 0;
25002		this.init();
25003	};
25004
25005	$.extend($.SmartMenus, {
25006		hideAll: function() {
25007			$.each(menuTrees, function() {
25008				this.menuHideAll();
25009			});
25010		},
25011		destroy: function() {
25012			while (menuTrees.length) {
25013				menuTrees[0].destroy();
25014			}
25015			initMouseDetection(true);
25016		},
25017		prototype: {
25018			init: function(refresh) {
25019				var self = this;
25020
25021				if (!refresh) {
25022					menuTrees.push(this);
25023
25024					this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
25025
25026					if (this.$root.hasClass('sm-rtl')) {
25027						this.opts.rightToLeftSubMenus = true;
25028					}
25029
25030					// init root (main menu)
25031					this.$root
25032						.data('smartmenus', this)
25033						.attr('data-smartmenus-id', this.rootId)
25034						.dataSM('level', 1)
25035						.bind({
25036							// 'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
25037							// 'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
25038							'mouseover.smartmenus': $.proxy(this.rootOver, this),
25039							'mouseout.smartmenus': $.proxy(this.rootOut, this)
25040						})
25041						.delegate('a, div.logo-container', {
25042							'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
25043							'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
25044							'mousedown.smartmenus': $.proxy(this.itemDown, this),
25045							'focus.smartmenus': $.proxy(this.itemFocus, this),
25046							'blur.smartmenus': $.proxy(this.itemBlur, this),
25047							'click.smartmenus': $.proxy(this.itemClick, this),
25048							'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
25049						});
25050
25051					var eNamespace = '.smartmenus' + this.rootId;
25052					// hide menus on tap or click outside the root UL
25053					if (this.opts.hideOnClick) {
25054							$(document).on('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
25055								.on('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
25056								.on('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
25057								// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
25058								.on('click' + eNamespace, $.proxy(this.docClick, this));
25059					}
25060					// hide sub menus on resize
25061					$(window).on('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
25062					var $vmenu = $('body.vmenu .vmenu-container');
25063					if ( ! $vmenu.length && UNCODE.wwidth > UNCODE.mediaQuery ) {
25064						$(window).on('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
25065					}
25066
25067					if (this.opts.subIndicators) {
25068						this.$subArrow = $('<span/>').addClass('sub-arrow');
25069						if (this.opts.subIndicatorsText) {
25070							this.$subArrow.html(this.opts.subIndicatorsText);
25071						}
25072					}
25073
25074					// make sure mouse detection is enabled
25075					initMouseDetection();
25076				}
25077
25078				// init sub menus
25079				this.$firstSub = this.$root.find('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').each(function() { self.menuInit($(this)); }).eq(0);
25080
25081				this.$firstLink = this.$root.find('a').eq(0);
25082
25083				// find current item
25084				if (this.opts.markCurrentItem) {
25085					var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
25086						reHash = /#.*/,
25087						locHref = window.location.href.replace(reDefaultDoc, ''),
25088						locHrefNoHash = locHref.replace(reHash, '');
25089					this.$root.find('a').each(function() {
25090						var href = this.href.replace(reDefaultDoc, ''),
25091							$this = $(this);
25092						if (href == locHref || href == locHrefNoHash) {
25093							$this.addClass('current');
25094							if (self.opts.markCurrentTree) {
25095								$this.parents('li').each(function() {
25096									var $this = $(this);
25097									if ($this.dataSM('sub')) {
25098										$this.children('a').addClass('current');
25099									}
25100								});
25101							}
25102						}
25103					});
25104				}
25105			},
25106			destroy: function() {
25107				this.menuHideAll();
25108				this.$root
25109					.removeData('smartmenus')
25110					.removeAttr('data-smartmenus-id')
25111					.removeDataSM('level')
25112					.unbind('.smartmenus')
25113					.undelegate('.smartmenus');
25114				var eNamespace = '.smartmenus' + this.rootId;
25115				$(document).unbind(eNamespace);
25116				$(window).unbind(eNamespace);
25117				if (this.opts.subIndicators) {
25118					this.$subArrow = null;
25119				}
25120				var self = this;
25121				$.each(this.subMenus, function() {
25122					if (this.hasClass('mega-menu')) {
25123						this.find('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').removeDataSM('in-mega');
25124					}
25125					if (this.dataSM('shown-before')) {
25126						if (IElt8) {
25127							this.children().css({ styleFloat: '', width: '' });
25128						}
25129						if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
25130							if (!IE6) {
25131								this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
25132							} else {
25133								this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
25134							}
25135						}
25136						if (this.dataSM('scroll-arrows')) {
25137							this.dataSM('scroll-arrows').remove();
25138						}
25139						this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
25140					}
25141					if (self.opts.subIndicators) {
25142						this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
25143					}
25144					this.removeDataSM('shown-before')
25145						.removeDataSM('ie-shim')
25146						.removeDataSM('scroll-arrows')
25147						.removeDataSM('parent-a')
25148						.removeDataSM('level')
25149						.removeDataSM('beforefirstshowfired')
25150						.parent().removeDataSM('sub');
25151				});
25152				if (this.opts.markCurrentItem) {
25153					this.$root.find('a.current').removeClass('current');
25154				}
25155				this.$root = null;
25156				this.$firstLink = null;
25157				this.$firstSub = null;
25158				if (this.$disableOverlay) {
25159					this.$disableOverlay.remove();
25160					this.$disableOverlay = null;
25161				}
25162				menuTrees.splice($.inArray(this, menuTrees), 1);
25163			},
25164			disable: function(noOverlay) {
25165				if (!this.disabled) {
25166					this.menuHideAll();
25167					// display overlay over the menu to prevent interaction
25168					if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
25169						var pos = this.$root.offset();
25170						this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
25171							position: 'absolute',
25172							top: pos.top,
25173							left: pos.left,
25174							width: this.$root.outerWidth(),
25175							height: this.$root.outerHeight(),
25176							zIndex: this.getStartZIndex() + 1,
25177							opacity: 0
25178						}).appendTo(document.body);
25179					}
25180					this.disabled = true;
25181				}
25182			},
25183			docClick: function(e) {
25184				// hide on any click outside the menu or on a menu link
25185				if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a:not([data-filter])')) {
25186					this.menuHideAll($(e.target));
25187				}
25188			},
25189			docTouchEnd: function(e) {
25190				if (!this.lastTouch) {
25191					return;
25192				}
25193				if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) {
25194					if (this.hideTimeout) {
25195						clearTimeout(this.hideTimeout);
25196						this.hideTimeout = 0;
25197					}
25198					// hide with a delay to prevent triggering accidental unwanted click on some page element
25199					var self = this;
25200					this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350);
25201				}
25202				this.lastTouch = null;
25203			},
25204			docTouchMove: function(e) {
25205				if (!this.lastTouch) {
25206					return;
25207				}
25208				var touchPoint = e.originalEvent.touches[0];
25209				this.lastTouch.x2 = touchPoint.pageX;
25210				this.lastTouch.y2 = touchPoint.pageY;
25211			},
25212			docTouchStart: function(e) {
25213				var touchPoint = e.originalEvent.touches[0];
25214				this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
25215			},
25216			enable: function() {
25217				if (this.disabled) {
25218					if (this.$disableOverlay) {
25219						this.$disableOverlay.remove();
25220						this.$disableOverlay = null;
25221					}
25222					this.disabled = false;
25223				}
25224			},
25225			getHeight: function($elm) {
25226				return this.getOffset($elm, true);
25227			},
25228			// returns precise width/height float values in IE9+, FF4+, recent WebKit
25229			// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
25230			getOffset: function($elm, height) {
25231				var old,
25232					$win = $(window),
25233					winW = $win.width();
25234				if ($elm.css('display') == 'none') {
25235					old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
25236					$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
25237					if ( 
25238						($('body').hasClass('menu-mobile-off-canvas') && winW < 960 && $elm.closest('.main-menu-container').length)
25239						||
25240						(( $('body').hasClass('vmenu-offcanvas-overlay') || $('body').hasClass('vmenu') ) && winW >= 960 && $elm.closest('.main-menu-container').length && !$elm.closest('.menu-horizontal-inner').length)
25241					) {
25242						$elm.closest('li').addClass('smartmenu-open-item');
25243					}
25244				}
25245				var defaultView = $elm[0].ownerDocument.defaultView,
25246					compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
25247					val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
25248				if (val) {
25249					val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
25250	 					+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
25251	 					+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
25252	 					+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
25253				} else {
25254					val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
25255				}
25256				if (old) {
25257					$elm.hide().css(old);
25258				}
25259				return val;
25260			},
25261			getWidth: function($elm) {
25262				return this.getOffset($elm);
25263			},
25264			getStartZIndex: function() {
25265				var zIndex = parseInt(this.$root.css('z-index'));
25266				return !isNaN(zIndex) ? zIndex : 1;
25267			},
25268			handleEvents: function() {
25269				return !this.disabled && this.isCSSOn();
25270			},
25271			handleItemEvents: function($a) {
25272				return this.handleEvents() && !this.isLinkInMegaMenu($a);
25273			},
25274			isCollapsible: function() {
25275				return this.$firstSub.css('position') == 'static';
25276			},
25277			isCSSOn: function() {
25278				return this.$firstLink.css('display') == 'block' || this.$firstLink.css('display') == 'flex' || this.$firstLink.css('display') == 'inline-flex' || this.$firstLink.css('display') == 'table-cell' || this.$firstLink.css('display') == 'inline';
25279			},
25280			isFixed: function() {
25281				return this.$root.css('position') == 'fixed';
25282			},
25283			isLinkInMegaMenu: function($a) {
25284				return !$a.parent().parent().dataSM('level');
25285			},
25286			isTouchMode: function() {
25287				return !mouse || this.isCollapsible();
25288			},
25289			itemActivate: function($a, $show) {
25290				var $li = $a.parent(),
25291					$ul = $li.parent(),
25292					level = $ul.dataSM('level'),
25293					winh = $(window).height();
25294				// if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first
25295				if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
25296					var self = this;
25297					$($ul.parentsUntil('[data-smartmenus-id]', 'ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').get().reverse()).add($ul).each(function() {
25298						self.itemActivate($(this).dataSM('parent-a'));
25299					});
25300				}
25301				// hide any visible deeper level sub menus
25302				if (this.visibleSubMenus.length > level) {
25303					for (var i = this.visibleSubMenus.length - 1, l = !this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level; i > l; i--) {
25304						this.lastLevel = level;
25305						if ( typeof $show === 'undefined' && this.isCollapsible() ) {
25306							this.menuHide(this.visibleSubMenus[i], $a);
25307							return;
25308						} else {
25309							this.menuHide(this.visibleSubMenus[i]);
25310						}
25311					}
25312				}
25313				// save new active item and sub menu for this level
25314				this.activatedItems[level - 1] = $a;
25315				this.visibleSubMenus[level - 1] = $ul;
25316				if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
25317					return;
25318				}
25319				// show the sub menu if this item has one
25320				var $sub = $li.dataSM('sub');
25321				if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
25322				// if ($sub && (this.isTouchMode() || (!this.opts.showOnClick))) {
25323					var aRect = $a[0].getBoundingClientRect();
25324					if ( (aRect.y < 0 || aRect.y > winh) && this.isCollapsible() && (this.lastLevel === this.activatedItems.length) ) {
25325						setTimeout(function(){
25326							var currentScroll = $a.closest('.main-menu-container').scrollTop();
25327							$a.closest('.main-menu-container').scrollTop(currentScroll + aRect.y);
25328						}, 1);
25329					}
25330					this.menuShow($sub);
25331				}
25332			},
25333			itemBlur: function(e) {
25334				var $a = $(e.currentTarget);
25335				if (!this.handleItemEvents($a)) {
25336					return;
25337				}
25338				this.$root.triggerHandler('blur.smapi', $a[0]);
25339			},
25340			itemClick: function(e) {
25341				var $a = $(e.currentTarget);
25342
25343				if (!this.handleItemEvents($a)) {
25344					return;
25345				}
25346				$a.removeDataSM('mousedown');
25347				if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
25348					return false;
25349				}
25350				var $sub = $a.parent().dataSM('sub');
25351				if (this.isTouchMode()) {
25352					// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
25353					if ($a.dataSM('href')) {
25354						$a.attr('href', $a.dataSM('href')).removeDataSM('href');
25355					}
25356					// if the sub is not visible
25357					if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
25358						// try to activate the item and show the sub
25359						this.itemActivate($a);
25360						// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
25361						// if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded
25362						if ($sub.is(':visible')) {
25363							return false;
25364						}
25365					}
25366				// } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub && !$sub.is(':visible')) {
25367				} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
25368					this.clickActivated = true;
25369					this.menuShow($sub);
25370					return false;
25371				}
25372				if ($a.hasClass('disabled')) {
25373					return false;
25374				}
25375				if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
25376					return false;
25377				}
25378			},
25379			itemDown: function(e) {
25380				var $a = $(e.currentTarget);
25381				if (!this.handleItemEvents($a)) {
25382					return;
25383				}
25384				$a.dataSM('mousedown', true);
25385			},
25386			itemEnter: function(e) {
25387				// if ( this.opts.showOnClick ) {
25388				// 	return
25389				// }
25390				var $a = $(e.currentTarget);
25391				if (!this.handleItemEvents($a)) {
25392					return;
25393				}
25394				if (!this.isTouchMode()) {
25395					if (this.showTimeout) {
25396						clearTimeout(this.showTimeout);
25397						this.showTimeout = 0;
25398					}
25399					var self = this;
25400					this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
25401				}
25402				this.$root.triggerHandler('mouseenter.smapi', $a[0]);
25403			},
25404			itemFocus: function(e) {
25405				var $a = $(e.currentTarget);
25406				if (!this.handleItemEvents($a)) {
25407					return;
25408				}
25409				// fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus
25410				if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
25411					this.itemActivate($a);
25412				}
25413				this.$root.triggerHandler('focus.smapi', $a[0]);
25414			},
25415			itemLeave: function(e) {
25416				// if ( this.opts.showOnClick ) {
25417				// 	return
25418				// }
25419				var $a = $(e.currentTarget);
25420				if (!this.handleItemEvents($a)) {
25421					return;
25422				}
25423				if (!this.isTouchMode()) {
25424					if ($a[0].blur) {
25425						$a[0].blur();
25426					}
25427					if (this.showTimeout) {
25428						clearTimeout(this.showTimeout);
25429						this.showTimeout = 0;
25430					}
25431				}
25432				$a.removeDataSM('mousedown');
25433				this.$root.triggerHandler('mouseleave.smapi', $a[0]);
25434			},
25435			itemTouchEnd: function(e) {
25436				var $a = $(e.currentTarget);
25437				if (!this.handleItemEvents($a)) {
25438					return;
25439				}
25440				// prevent the address bar on iPhone from sliding down when expanding a sub menu
25441				var $sub = $a.parent().dataSM('sub');
25442				if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
25443					$a.dataSM('href', $a.attr('href'));
25444					$a.attr('href', '#');
25445				}
25446			},
25447			menuFixLayout: function($ul) {
25448				// fixes a menu that is being shown for the first time
25449				if (!$ul.dataSM('shown-before')) {
25450					$ul.hide().dataSM('shown-before', true);
25451					// fix the layout of the items in IE<8
25452					if (IElt8) {
25453						$ul.children().css({ styleFloat: 'left', width: '100%' });
25454					}
25455				}
25456			},
25457			menuHide: function($sub, $show) {
25458				if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
25459					return;
25460				}
25461				$sub.stop(true, true);
25462				if ($sub.is(':visible')) {
25463					var self = this;
25464					var complete = function() {
25465						// unset z-index
25466						if (IElt9) {
25467							$sub.parent().css('z-index', '');
25468						} else {
25469							$sub.css('z-index', '');
25470						}
25471						if ( typeof $show !== 'undefined' ) {
25472							self.itemActivate($show, true)
25473						}
25474					};
25475					// if sub is collapsible (mobile view)
25476					if (this.isCollapsible()) {
25477						if (this.opts.collapsibleHideFunction) {
25478							this.opts.collapsibleHideFunction.call(this, $sub, complete);
25479						} else {
25480							$sub.hide(this.opts.collapsibleHideDuration, complete);
25481						}
25482					} else {
25483						if (this.opts.hideFunction) {
25484							this.opts.hideFunction.call(this, $sub, complete);
25485						} else {
25486							$sub.hide(this.opts.hideDuration, complete);
25487						}
25488					}
25489					// remove IE iframe shim
25490					if ($sub.dataSM('ie-shim')) {
25491						$sub.dataSM('ie-shim').remove();
25492					}
25493					// deactivate scrolling if it is activated for this sub
25494					if ($sub.dataSM('scroll')) {
25495						$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
25496					}
25497					// unhighlight parent item
25498					$sub.dataSM('parent-a').removeClass('highlighted');
25499					var level = $sub.dataSM('level');
25500					this.activatedItems.splice(level - 1, 1);
25501					this.visibleSubMenus.splice(level - 1, 1);
25502					this.$root.triggerHandler('hide.smapi', $sub[0]);
25503				}
25504			},
25505			menuHideAll: function($item) {
25506				if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return;
25507				var $win = $(window),
25508					winW = $win.width();
25509				if (this.showTimeout) {
25510					clearTimeout(this.showTimeout);
25511					this.showTimeout = 0;
25512				}
25513				// hide all subs
25514				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
25515					if ( this.visibleSubMenus[i].closest('.smartmenu-open-item').length ) {
25516						if ( $item != undefined && $item.closest('.smartmenu-open-item').length ) {
25517							this.menuHide(this.visibleSubMenus[i]);
25518							$(this.visibleSubMenus[i]).closest('.smartmenu-open-item').removeClass('smartmenu-open-item');
25519						} else {
25520							return;
25521						}
25522					} else {
25523						//if ( !this.visibleSubMenus[i].closest('.menu-accordion').length ) {
25524							this.menuHide(this.visibleSubMenus[i]);
25525						//}
25526					}
25527				}
25528				// hide root if it's popup
25529				if (this.opts.isPopup) {
25530					this.$root.stop(true, true);
25531					if (this.$root.is(':visible')) {
25532						if (this.opts.hideFunction) {
25533							this.opts.hideFunction.call(this, this.$root);
25534						} else {
25535							this.$root.hide(this.opts.hideDuration);
25536						}
25537						// remove IE iframe shim
25538						if (this.$root.dataSM('ie-shim')) {
25539							this.$root.dataSM('ie-shim').remove();
25540						}
25541					}
25542				}
25543				this.activatedItems = [];
25544				this.visibleSubMenus = [];
25545				this.clickActivated = false;
25546				// reset z-index increment
25547				this.zIndexInc = 0;
25548			},
25549			menuIframeShim: function($ul) {
25550				// create iframe shim for the menu
25551				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
25552					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
25553						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
25554					);
25555				}
25556			},
25557			menuInit: function($ul) {
25558				if (!$ul.dataSM('in-mega')) {
25559					this.subMenus.push($ul);
25560					// mark UL's in mega drop downs (if any) so we can neglect them
25561					if ($ul.hasClass('mega-menu')) {
25562						$ul.find('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').dataSM('in-mega', true);
25563					}
25564					// get level (much faster than, for example, using parentsUntil)
25565					var level = 2,
25566						par = $ul[0];
25567					while (par != null && par.parentNode != null && ( par = par.parentNode.parentNode) != this.$root[0]) {
25568						level++;
25569					}
25570					// cache stuff
25571					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
25572						.dataSM('level', level)
25573						.parent().dataSM('sub', $ul);
25574					// add sub indicator to parent item
25575					if (this.opts.subIndicators) {
25576						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
25577					}
25578				}
25579				if ( $('.vc_row[data-parent].has-bg', $ul).length && !$('.vc_row[data-parent]:not(.has-bg)', $ul).length ) {
25580					$ul.addClass('has-bg-items');
25581				}
25582			},
25583			menuPosition: function($sub) {
25584				var fixIE = $('html.ie').length;
25585				// if (fixIE) {
25586				// 	var $rowParent = $($sub).closest('.main-menu-container');
25587				// 	$rowParent.height($rowParent.height());
25588				// }
25589				var $a = $sub.dataSM('parent-a'),
25590					$li = $sub.parent(),
25591					$ul = $sub.parent().parent(),
25592					// $container = $ul.closest('.row-menu-inner').length ? ( $('body').hasClass('megamenu-side-to-side') ? ( $('body').hasClass('boxed-width') ? $ul.closest('.row-menu') : $(window) ) : $ul.closest('.row-menu-inner') ) : $ul.closest('.uncol'),
25593					$container = $ul.closest('.row-menu-inner').length ? ( $('body').hasClass('megamenu-side-to-side') ? $ul.closest('.row-menu') : $ul.closest('.row-menu-inner') ) : $ul.closest('.uncol'),
25594					level = $sub.dataSM('level'),
25595					subW = this.getWidth($sub),
25596					subH = this.getHeight($sub),
25597					itemOffset = $a.offset(),
25598					itemX = itemOffset.left,
25599					itemY = itemOffset.top,
25600					itemW = this.getWidth($a),
25601					itemH = this.getHeight($a),
25602					$win = $(window),
25603					winX = $win.scrollLeft(),
25604					winY = $win.scrollTop(),
25605					winW = $win.width(),
25606					winH = $win.height(),
25607					containerW = $container.width(),
25608					containerOffsetX = containerW + ((winW - containerW) / 2),
25609					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
25610					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
25611					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
25612					x, y, leftPos;
25613
25614				if (horizontalParent) {
25615					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
25616					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
25617				} else {
25618					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : subW - subOffsetX;
25619					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
25620				}
25621				if (this.opts.keepInViewport && !this.isCollapsible()) {
25622					if (this.isFixed()) {
25623						itemX -= winX;
25624						itemY -= winY;
25625						winX = winY = 0;
25626					}
25627					var absX = itemX + x,
25628						absY = itemY + y;
25629					if (this.opts.rightToLeftSubMenus && absX < winX) {
25630						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
25631					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
25632						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
25633					}
25634					if (!horizontalParent) {
25635						if (subH < winH && absY + subH > winY + winH) {
25636							y += winY + winH - subH - absY;
25637						} else if (subH >= winH || absY < winY) {
25638							y += winY - absY;
25639						}
25640					}
25641					// do we need scrolling?
25642					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
25643					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
25644						var self = this;
25645						if (!$sub.dataSM('scroll-arrows')) {
25646							$sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]])
25647								.bind({
25648									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
25649									mouseleave: function(e) {
25650										self.menuScrollStop($sub);
25651										self.menuScrollOut($sub, e);
25652									},
25653									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
25654								})
25655								.insertAfter($sub)
25656							);
25657						}
25658						// bind events to show/hide arrows on hover and save scrolling data for this sub
25659						var vportY = winY - (itemY + itemH);
25660						$sub.dataSM('scroll', {
25661								vportY: vportY,
25662								subH: subH,
25663								winH: winH,
25664								step: 1
25665							})
25666							.bind({
25667								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
25668								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
25669								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
25670							})
25671							.dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: this.getWidth($sub) - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: this.get
25671StartZIndex() + this.zIndexInc })
25672							.eq(0).css('margin-top', vportY).end()
25673							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
25674							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
25675					}
25676				}
25677				if ( !$sub.closest('.menu-accordion').length ) {
25678					var rightPos = 'auto';
25679					if ( $sub.closest('.grid-filters').length ) {
25680						if ( $sub.closest('.text-right').length ) {
25681							leftPos = '0px';
25682							rightPos = 'auto';
25683						} else {
25684							leftPos = 'auto';
25685							rightPos = '0px';
25686						}
25687						x = 0;
25688					} else {
25689						if ( $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)').length && $sub.closest('.row-menu').is('.limit-width') && level === 2) {
25690							var parentContW = $sub.closest('.menu-container').width();
25691							$sub.css({ width: parentContW});
25692							$sub.addClass('need-focus');
25693							leftPos = -1 * (parseFloat($sub.closest('ul.menu-smart').offset().left) - parseFloat($sub.closest('.menu-container').offset().left));
25694							x = 0;
25695						} else if ( $sub.hasClass('mega-menu-inner') || $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)').length ) {
25696							$sub.css({ width: containerW});
25697							$sub.addClass('need-focus');
25698							leftPos = -1 * (parseFloat($sub.closest('ul.menu-smart').offset().left) - parseFloat($sub.closest('.row-menu').offset().left));
25699							if ( ! $('body').hasClass('megamenu-side-to-side') ) {
25700								leftPos += parseFloat($sub.closest('.row-menu-inner').css('paddingLeft'));
25701							}
25702							x = 0;
25703						} else {
25704							if ( $sub.is('.block-wrapper-parent') && !$sub.find('.col-custom-width').length && !$sub.find('.row-parent-limit').length && level === 2 ) {
25705								leftPos = ( $li.position().left - ( (UNCODE.wwidth - $sub.outerWidth() )/2) ) + 'px';
25706							} else {
25707								leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').css('paddingLeft')) : $li.position().left ) + 'px';
25708							}
25709							x = (level > 2 && x >= 0) ? x + 1 : x - 1;
25710						}
25711					}
25712				}
25713
25714				// $sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-borders').length ? 1 : 0) });
25715				$sub.css({ top: (level > 2) ? $a[0].offsetTop : (fixIE ? itemH : '100%'), left: leftPos, right: rightPos, marginLeft: x, marginTop: (level > 2) ? 0 : y - itemH + ($sub.closest('.menu-borders').length && !$sub.closest('.menu-borders.needs-after').length ? 1 : 0) });
25716				// IE iframe shim
25717				this.menuIframeShim($sub);
25718				if ($sub.dataSM('ie-shim')) {
25719					$sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH + ($sub.closest('.menu-mini').length ? 0 : 1) });
25720				}
25721			},
25722			menuScroll: function($sub, up, wheel) {
25723				var y = parseFloat($sub.css('margin-top')),
25724					scroll = $sub.dataSM('scroll'),
25725					navH = $('.navbar-main').outerHeight(),
25726					end = scroll.vportY + (up ? navH + 54 : scroll.winH - scroll.subH),
25727					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
25728				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
25729				y = parseFloat($sub.css('margin-top'));
25730				// show opposite arrow if appropriate
25731				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
25732					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
25733				}
25734				// accelerate when not using mousewheel to scroll
25735				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
25736					$sub.dataSM('scroll').step += 0.5;
25737				}
25738				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
25739				if (Math.abs(y - end) < 1) {
25740					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
25741					$sub.dataSM('scroll').step = 1;
25742				} else if (!wheel) {
25743					var self = this;
25744					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
25745				}
25746			},
25747			menuScrollMousewheel: function($sub, e) {
25748				var $closestSub = $(e.target).closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25749				while ($closestSub.dataSM('in-mega')) {
25750					$closestSub = $closestSub.parent().closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25751				}
25752				if ($closestSub[0] == $sub[0]) {
25753					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
25754					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
25755						this.menuScroll($sub, up, true);
25756					}
25757				}
25758				if ( ! $sub.hasClass('mega-menu-inner') && ! $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)') ) {
25759					e.preventDefault();
25760				}
25761			},
25762			menuScrollOut: function($sub, e) {
25763				var reClass = /^scroll-(up|down)/,
25764					$closestSub = $(e.relatedTarget).closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25765				while ($closestSub.dataSM('in-mega')) {
25766					$closestSub = $closestSub.parent().closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25767				}
25768				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
25769					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
25770				}
25771			},
25772			menuScrollOver: function($sub, e) {
25773				var reClass = /^scroll-(up|down)/,
25774					$closestSub = $(e.target).closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25775				while ($closestSub.dataSM('in-mega')) {
25776					$closestSub = $closestSub.parent().closest('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)');
25777				}
25778				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
25779					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
25780				}
25781			},
25782			menuScrollStop: function($sub) {
25783				if (this.scrollTimeout) {
25784					clearTimeout(this.scrollTimeout);
25785					this.scrollTimeout = 0;
25786					$sub.dataSM('scroll').step = 1;
25787				}
25788			},
25789			menuShow: function($sub) {
25790				if (!$sub.dataSM('beforefirstshowfired')) {
25791					$sub.dataSM('beforefirstshowfired', true);
25792					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
25793						return;
25794					}
25795				}
25796				if ( this.isCollapsible() ) {
25797					this.$root.triggerHandler('beforecollapse.smapi', $sub[0]);
25798				}
25799				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
25800					return;
25801				}
25802				this.menuFixLayout($sub);
25803				$sub.stop(true, true);
25804				if (!$sub.is(':visible')) {
25805					$sub.css({
25806						'visibility': 'visible',
25807						'pointer-events': 'auto',
25808					});
25809					// set z-index - for IE < 9 set it to the parent LI
25810					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
25811					if (IElt9) {
25812						$sub.parent().css('z-index', zIndex);
25813					} else {
25814						$sub.css('z-index', zIndex);
25815					}
25816					// highlight parent item
25817					if (this.opts.keepHighlighted || this.isCollapsible()) {
25818						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
25819							$sub.dataSM('parent-a').addClass('highlighted');
25820					}
25821					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
25822					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
25823						if (!IElt8) {
25824							$sub.css({ width: ($sub.hasClass('mega-menu-inner') || $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
25825							if (this.opts.subMenusMinWidth) {
25826							 	$sub.css('min-width', this.opts.subMenusMinWidth);
25827							}
25828							if (this.opts.subMenusMaxWidth) {
25829							 	var noMaxWidth = this.getWidth($sub);
25830							 	if ( ! $sub.hasClass('mega-menu-inner') && ! $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)') ) {
25831								 	$sub.css('max-width', this.opts.subMenusMaxWidth);
25832							 	}
25833								if (noMaxWidth > this.getWidth($sub)) {
25834									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
25835								}
25836							}
25837						// IE6,7
25838 						} else {
25839							$sub.children().css('styleFloat', 'none');
25840							if (IE6) {
25841								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
25842									.children().children('a').css('white-space', 'nowrap');
25843							} else { // IE7
25844								$sub.css({ width: ($sub.hasClass('mega-menu-inner') || $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
25845								if (this.opts.subMenusMinWidth) {
25846									$sub.css('min-width', this.opts.subMenusMinWidth);
25847								}
25848							}
25849							if (this.opts.subMenusMaxWidth) {
25850								var noMaxWidth = $sub.width();
25851								if (IE6) {
25852							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
25853									if (noMaxWidth > maxWidth) {
25854										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
25855									} else {
25856										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
25857									}
25858								} else { // IE7
25859								 	if ( ! $sub.hasClass('mega-menu-inner') && ! $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)') ) {
25860									 	$sub.css('max-width', this.opts.subMenusMaxWidth);
25861								 	}
25862									if (noMaxWidth > $sub.width()) {
25863										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
25864									} else {
25865										$sub.width(noMaxWidth);
25866									}
25867								}
25868							} else {
25869							 	$sub.width($sub.width());
25870							}
25871							$sub.children().css('styleFloat', 'left');
25872						}
25873					}
25874					if ( ( ( ($sub.hasClass('mega-menu-inner') || $sub.find('[data-parent="true"]:not(.limit-width):not(.row-parent-limit)')) && $('body').hasClass('scrollable-megamenu') ) ) && UNCODE.wwidth > UNCODE.mediaQuery ) {
25875						var $nav = $('.navbar-main'),
25876							navH = 0,
25877							navTop = 0,
25878							$vmenu = $('body.vmenu .vmenu-container, body.menu-overlay .vmenu-container, body.menu-offcanvas .vmenu-container');
25879						if ( $nav.length && typeof $nav[0] !== 'undefined' ) {
25880							var navRect = $nav[0].getBoundingClientRect();
25881							navH = navRect.height;
25882							navTop = navRect.top;
25883						}
25884						if ( ! $vmenu.length ) {
25885							$sub.css({ maxHeight: UNCODE.wheight - navH });
25886							if ( $('.megamenu-block-wrapper', $sub).length ) {
25887								$sub.find('> li').addClass('has-scroll').css({ maxHeight: UNCODE.wheight - navH });
25888							}
25889						}
25890					}
25891					this.menuPosition($sub);
25892					// insert IE iframe shim
25893					if ($sub.dataSM('ie-shim')) {
25894						$sub.dataSM('ie-shim').insertBefore($sub);
25895					}
25896					var complete = function() {
25897						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
25898						$sub.css('overflow', '');
25899					};
25900					// if sub is collapsible (mobile view)
25901					if (this.isCollapsible()) {
25902						if (this.opts.collapsibleShowFunction) {
25903							this.opts.collapsibleShowFunction.call(this, $sub, complete);
25904						} else {
25905							$sub.show(this.opts.collapsibleShowDuration, complete);
25906						}
25907					} else {
25908						if (this.opts.showFunction) {
25909							this.opts.showFunction.call(this, $sub, complete);
25910						} else {
25911							$sub.show(this.opts.showDuration, complete);
25912						}
25913					}
25914					// save new sub menu for this level
25915					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
25916					this.$root.triggerHandler('show.smapi', $sub[0]);
25917				}
25918			},
25919			popupHide: function(noHideTimeout) {
25920				if (this.hideTimeout) {
25921					clearTimeout(this.hideTimeout);
25922					this.hideTimeout = 0;
25923				}
25924				var self = this;
25925				this.hideTimeout = setTimeout(function() {
25926					self.menuHideAll();
25927				}, noHideTimeout ? 1 : this.opts.hideTimeout);
25928			},
25929			popupShow: function(left, top) {
25930				if (!this.opts.isPopup) {
25931					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
25932					return;
25933				}
25934				if (this.hideTimeout) {
25935					clearTimeout(this.hideTimeout);
25936					this.hideTimeout = 0;
25937				}
25938				this.menuFixLayout(this.$root);
25939				this.$root.stop(true, true);
25940				if (!this.$root.is(':visible')) {
25941					this.$root.css({ left: left, top: top });
25942					// IE iframe shim
25943					this.menuIframeShim(this.$root);
25944					if (this.$root.dataSM('ie-shim')) {
25945						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
25945: left, top: top }).insertBefore(this.$root);
25946					}
25947					// show menu
25948					if (this.opts.showFunction) {
25949						this.opts.showFunction.call(this, this.$root);
25950					} else {
25951						this.$root.show(this.opts.showDuration);
25952					}
25953					this.visibleSubMenus[0] = this.$root;
25954				}
25955			},
25956			refresh: function() {
25957				this.menuHideAll();
25958				this.$root.find('ul:not(.nav-tabs):not(.unmenu-block):not(.unmenu-block *)').each(function() {
25959						var $this = $(this);
25960						if ($this.dataSM('scroll-arrows')) {
25961							$this.dataSM('scroll-arrows').remove();
25962						}
25963					})
25964					.removeDataSM('in-mega')
25965					.removeDataSM('shown-before')
25966					.removeDataSM('ie-shim')
25967					.removeDataSM('scroll-arrows')
25968					.removeDataSM('parent-a')
25969					.removeDataSM('level')
25970					.removeDataSM('beforefirstshowfired');
25971				this.$root.find('a.has-submenu').removeClass('has-submenu')
25972					.parent().removeDataSM('sub');
25973				if (this.opts.subIndicators) {
25974					this.$root.find('span.sub-arrow').remove();
25975				}
25976				if (this.opts.markCurrentItem) {
25977					this.$root.find('a.current').removeClass('current');
25978				}
25979				this.subMenus = [];
25980				this.init(true);
25981			},
25982			rootOut: function(e) {
25983				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
25984					return;
25985				}
25986				if (this.hideTimeout) {
25987					clearTimeout(this.hideTimeout);
25988					this.hideTimeout = 0;
25989				}
25990				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
25991					var self = this;
25992					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
25993				}
25994			},
25995			rootOver: function(e) {
25996				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
25997					return;
25998				}
25999				if (this.hideTimeout) {
26000					clearTimeout(this.hideTimeout);
26001					this.hideTimeout = 0;
26002				}
26003			},
26004			winResize: function(e) {
26005				if (!this.handleEvents()) {
26006					// we still need to resize the disable overlay if it's visible
26007					if (this.$disableOverlay) {
26008						var pos = this.$root.offset();
26009	 					this.$disableOverlay.css({
26010							top: pos.top,
26011							left: pos.left,
26012							width: this.$root.outerWidth(),
26013							height: this.$root.outerHeight()
26014						});
26015					}
26016					return;
26017				}
26018				// hide sub menus on resize - on mobile do it only on orientation change
26019				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
26020					if (this.activatedItems.length) {
26021						this.activatedItems[this.activatedItems.length - 1][0].blur();
26022					}
26023					this.menuHideAll();
26024				}
26025			}
26026		}
26027	});
26028
26029	$.fn.dataSM = function(key, val) {
26030		if (val) {
26031			return this.data(key + '_smartmenus', val);
26032		}
26033		return this.data(key + '_smartmenus');
26034	}
26035
26036	$.fn.removeDataSM = function(key) {
26037		return this.removeData(key + '_smartmenus');
26038	}
26039
26040	$.fn.smartmenus = function(options) {
26041		if (typeof options == 'string') {
26042			var args = arguments,
26043				method = options;
26044			Array.prototype.shift.call(args);
26045			return this.each(function() {
26046				var smartmenus = $(this).data('smartmenus');
26047				if (smartmenus && smartmenus[method]) {
26048					smartmenus[method].apply(smartmenus, args);
26049				}
26050			});
26051		}
26052		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
26053		return this.each(function() {
26054			new $.SmartMenus(this, opts);
26055		});
26056	}
26057
26058	// default settings
26059	$.fn.smartmenus.defaults = {
26060		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
26061		mainMenuSubOffsetX:	0,		// pixels offset from default position
26062		mainMenuSubOffsetY:	0,		// pixels offset from default position
26063		subMenusSubOffsetX:	0,		// pixels offset from default position
26064		subMenusSubOffsetY:	0,		// pixels offset from default position
26065		subMenusMinWidth:	false, //'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
26066		subMenusMaxWidth:	false, //'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
26067		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
26068		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
26069		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
26070		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
26071		scrollInterval:		30,		// interval between each scrolling step
26072		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
26073		showTimeout:		250,		// timeout before showing the sub menus
26074		hideTimeout:		500,		// timeout before hiding the sub menus
26075		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
26076		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
26077							// don't forget to call complete() at the end of whatever you do
26078							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
26079		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
26080		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
26081							// don't forget to call complete() at the end of whatever you do
26082							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
26083		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
26084		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
26085							// (i.e. when mobile styles are used to make the sub menus collapsible)
26086		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
26087		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
26088							// (i.e. when mobile styles are used to make the sub menus collapsible)
26089		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
26090		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
26091		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
26092		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
26093		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
26094		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
26095		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
26096		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
26097		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
26098	};
26099
26100})(jQuery);
26101/*
26102 * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/
26103 * Open source under the BSD License.
26104 * Copyright © 2008 George McGinley Smith
26105 * All rights reserved.
26106 * https://raw.github.com/gdsmith/jquery.easing/master/LICENSE
26107*/
26108
26109/* globals jQuery, define, module, require */
26110(function (factory) {
26111	if (typeof define === "function" && define.amd) {
26112		define(['jquery'], function ($) {
26113			return factory($);
26114		});
26115	} else if (typeof module === "object" && typeof module.exports === "object") {
26116		module.exports = factory(require('jquery'));
26117	} else {
26118		factory(jQuery);
26119	}
26120})(function($){
26121
26122	// Preserve the original jQuery "swing" easing as "jswing"
26123	if (typeof $.easing !== 'undefined') {
26124		$.easing['jswing'] = $.easing['swing'];
26125	}
26126
26127	var pow = Math.pow,
26128		sqrt = Math.sqrt,
26129		sin = Math.sin,
26130		cos = Math.cos,
26131		PI = Math.PI,
26132		c1 = 1.70158,
26133		c2 = c1 * 1.525,
26134		c3 = c1 + 1,
26135		c4 = ( 2 * PI ) / 3,
26136		c5 = ( 2 * PI ) / 4.5;
26137
26138	// x is the fraction of animation progress, in the range 0..1
26139	function bounceOut(x) {
26140		var n1 = 7.5625,
26141			d1 = 2.75;
26142		if ( x < 1/d1 ) {
26143			return n1*x*x;
26144		} else if ( x < 2/d1 ) {
26145			return n1*(x-=(1.5/d1))*x + .75;
26146		} else if ( x < 2.5/d1 ) {
26147			return n1*(x-=(2.25/d1))*x + .9375;
26148		} else {
26149			return n1*(x-=(2.625/d1))*x + .984375;
26150		}
26151	}
26152
26153	$.extend( $.easing, {
26154		def: 'easeOutQuad',
26155		swing: function (x) {
26156			return $.easing[$.easing.def](x);
26157		},
26158		easeInQuad: function (x) {
26159			return x * x;
26160		},
26161		easeOutQuad: function (x) {
26162			return 1 - ( 1 - x ) * ( 1 - x );
26163		},
26164		easeInOutQuad: function (x) {
26165			return x < 0.5 ?
26166				2 * x * x :
26167				1 - pow( -2 * x + 2, 2 ) / 2;
26168		},
26169		easeInCubic: function (x) {
26170			return x * x * x;
26171		},
26172		easeOutCubic: function (x) {
26173			return 1 - pow( 1 - x, 3 );
26174		},
26175		easeInOutCubic: function (x) {
26176			return x < 0.5 ?
26177				4 * x * x * x :
26178				1 - pow( -2 * x + 2, 3 ) / 2;
26179		},
26180		easeInQuart: function (x) {
26181			return x * x * x * x;
26182		},
26183		easeOutQuart: function (x) {
26184			return 1 - pow( 1 - x, 4 );
26185		},
26186		easeInOutQuart: function (x) {
26187			return x < 0.5 ?
26188				8 * x * x * x * x :
26189				1 - pow( -2 * x + 2, 4 ) / 2;
26190		},
26191		easeInQuint: function (x) {
26192			return x * x * x * x * x;
26193		},
26194		easeOutQuint: function (x) {
26195			return 1 - pow( 1 - x, 5 );
26196		},
26197		easeInOutQuint: function (x) {
26198			return x < 0.5 ?
26199				16 * x * x * x * x * x :
26200				1 - pow( -2 * x + 2, 5 ) / 2;
26201		},
26202		easeInSine: function (x) {
26203			return 1 - cos( x * PI/2 );
26204		},
26205		easeOutSine: function (x) {
26206			return sin( x * PI/2 );
26207		},
26208		easeInOutSine: function (x) {
26209			return -( cos( PI * x ) - 1 ) / 2;
26210		},
26211		easeInExpo: function (x) {
26212			return x === 0 ? 0 : pow( 2, 10 * x - 10 );
26213		},
26214		easeOutExpo: function (x) {
26215			return x === 1 ? 1 : 1 - pow( 2, -10 * x );
26216		},
26217		easeInOutExpo: function (x) {
26218			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
26219				pow( 2, 20 * x - 10 ) / 2 :
26220				( 2 - pow( 2, -20 * x + 10 ) ) / 2;
26221		},
26222		easeInCirc: function (x) {
26223			return 1 - sqrt( 1 - pow( x, 2 ) );
26224		},
26225		easeOutCirc: function (x) {
26226			return sqrt( 1 - pow( x - 1, 2 ) );
26227		},
26228		easeInOutCirc: function (x) {
26229			return x < 0.5 ?
26230				( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
26231				( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
26232		},
26233		easeInElastic: function (x) {
26234			return x === 0 ? 0 : x === 1 ? 1 :
26235				-pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
26236		},
26237		easeOutElastic: function (x) {
26238			return x === 0 ? 0 : x === 1 ? 1 :
26239				pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
26240		},
26241		easeInOutElastic: function (x) {
26242			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
26243				-( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
26244				pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
26245		},
26246		easeInBack: function (x) {
26247			return c3 * x * x * x - c1 * x * x;
26248		},
26249		easeOutBack: function (x) {
26250			return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
26251		},
26252		easeInOutBack: function (x) {
26253			return x < 0.5 ?
26254				( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
26255				( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
26256		},
26257		easeInBounce: function (x) {
26258			return 1 - bounceOut( 1 - x );
26259		},
26260		easeOutBounce: bounceOut,
26261		easeInOutBounce: function (x) {
26262			return x < 0.5 ?
26263				( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
26264				( 1 + bounceOut( 2 * x - 1 ) ) / 2;
26265		}
26266	});
26267	return $;
26268});
26269
26270/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
26271 * Licensed under the MIT License (LICENSE.txt).
26272 *
26273 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
26274 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
26275 * Thanks to: Seamus Leahy for adding deltaX and deltaY
26276 *
26277 * Version: 3.0.6
26278 *
26279 * Requires: 1.2.2+
26280 */
26281(function($) {
26282    var types = ['DOMMouseScroll', 'mousewheel'];
26283    if ($.event.fixHooks) {
26284        for (var i = types.length; i;) {
26285            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
26286        }
26287    }
26288    $.event.special.mousewheel = {
26289        setup: function() {
26290            if (this.addEventListener) {
26291                for (var i = types.length; i;) {
26292                    this.addEventListener(types[--i], handler, false);
26293                }
26294            } else {
26295                this.onmousewheel = handler;
26296            }
26297        },
26298        teardown: function() {
26299            if (this.removeEventListener) {
26300                for (var i = types.length; i;) {
26301                    this.removeEventListener(types[--i], handler, false);
26302                }
26303            } else {
26304                this.onmousewheel = null;
26305            }
26306        }
26307    };
26308    $.fn.extend({
26309        mousewheel: function(fn) {
26310            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
26311        },
26312        unmousewheel: function(fn) {
26313            return this.unbind("mousewheel", fn);
26314        }
26315    });
26316
26317    function handler(event) {
26318        var orgEvent = event || window.event,
26319            args = [].slice.call(arguments, 1),
26320            delta = 0,
26321            returnValue = true,
26322            deltaX = 0,
26323            deltaY = 0;
26324        event = $.event.fix(orgEvent);
26325        event.type = "mousewheel";
26326        // Old school scrollwheel delta
26327        if (orgEvent.wheelDelta) {
26328            delta = orgEvent.wheelDelta / 120;
26329        }
26330        if (orgEvent.detail) {
26331            delta = -orgEvent.detail / 3;
26332        }
26333        // New school multidimensional scroll (touchpads) deltas
26334        deltaY = delta;
26335        // Gecko
26336        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
26337            deltaY = 0;
26338            deltaX = -1 * delta;
26339        }
26340        // Webkit
26341        if (orgEvent.wheelDeltaY !== undefined) {
26342            deltaY = orgEvent.wheelDeltaY / 120;
26343        }
26344        if (orgEvent.wheelDeltaX !== undefined) {
26345            deltaX = -1 * orgEvent.wheelDeltaX / 120;
26346        }
26347        // Add event and delta to the front of the arguments
26348        args.unshift(event, delta, deltaX, deltaY);
26349        return ($.event.dispatch || $.event.handle).apply(this, args);
26350    }
26351})(jQuery);
26352/**
26353 * jQuery iLightBox - Revolutionary Lightbox Plugin
26354 * http://www.ilightbox.net/
26355 *
26356 * @version: 2.2.4 - October 14, 2017
26357 *
26358 * @author: iProDev (Hemn Chawroka)
26359 *          http://www.iprodev.com/
26360 *
26361 */
26362(function($, window, undefined) {
26363
26364	var extensions = {
26365			flash: ['swf'],
26366			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe', 'webp'],
26367			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
26368			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
26369		},
26370
26371		// Global DOM elements
26372		$win = $(window),
26373		$doc = $(document),
26374
26375		// Support indicators
26376		browser,
26377		transform,
26378		gpuAcceleration,
26379		fullScreenApi = '',
26380		userAgent = navigator.userAgent || navigator.vendor || window.opera,
26381        supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1),
26382        ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1,
26383        isMobile = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)),
26384
26385		// Events
26386		clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox",
26387		touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
26388		touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
26389		touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
26390
26391		// Math shorthands
26392		abs = Math.abs,
26393		sqrt = Math.sqrt,
26394		round = Math.round,
26395		max = Math.max,
26396		min = Math.min,
26397		floor = Math.floor,
26398		random = Math.random,
26399
26400		pluginspages = {
26401			quicktime: 'http://www.apple.com/quicktime/download',
26402			flash: 'http://www.adobe.com/go/getflash'
26403		},
26404
26405		iLightBox = function(el, options, items, instant) {
26406			var iL = this;
26407
26408			iL.options = options,
26409				iL.selector = options.selector || el,
26410				iL.context = document,
26411				iL.instant = instant;
26412
26413			if (items.length < 1) iL.attachItems();
26414			else iL.items = items;
26415
26416			iL.vars = {
26417				total: iL.items.length,
26418				start: 0,
26419				current: null,
26420				next: null,
26421				prev: null,
26422				BODY: $('body'),
26423				loadRequests: 0,
26424				overlay: $('<div class="ilightbox-overlay"></div>'),
26425				loader: $('<div class="ilightbox-loader"><div></div></div>'),
26426				toolbar: $('<div class="ilightbox-toolbar"></div>'),
26427				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
26428				title: $('<div class="ilightbox-title"></div>'),
26429				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
26430				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
26431				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
26432				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
26433				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
26434				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
26435				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
26436				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
26437				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
26438				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
26439				thumbnails: $('<div class="ilightbox-thumbnails" ondragstart="return false;"><div class="ilightbox-thumbnails-container"><a class="ilightbox-thumbnails-dragger"></a><div class="ilightbox-thumbnails-grid"></div></div></div>'),
26440				thumbs: false,
26441				nextLock: false,
26442				prevLock: false,
26443				hashLock: false,
26444				isMobile: false,
26445				mobileMaxWidth: 980,
26446				isInFullScreen: false,
26447				isSwipe: false,
26448				mouseID: 0,
26449				cycleID: 0,
26450				isPaused: 0,
26451				captionHeight: 39,
26452			};
26453
26454			// Hideable elements with mousemove event
26455			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
26456
26457			iL.normalizeItems();
26458
26459			//Check necessary plugins
26460			iL.availPlugins();
26461
26462			//Set startFrom
26463			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
26464
26465			//If randomStart
26466			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
26467			iL.vars.start = iL.options.startFrom;
26468
26469			if (instant) iL.instantCall();
26470			else iL.patchItemsEvents();
26471
26472			if (iL.options.linkId) {
26473				iL.hashChangeHandler();
26474				$win.iLightBoxHashChange(function() {
26475					iL.hashChangeHandler();
26476				});
26477			}
26478
26479			if (supportTouch) {
26480				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
26481					replace = "itap";
26482				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
26483					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
26484					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
26485					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
26486			}
26487
26488			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
26489				$.extend(iL.options.styles, {
26490					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
26491					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
26492					nextOpacity: 0,
26493					prevOpacity: 0
26494				});
26495			}
26496		};
26497
26498	//iLightBox helpers
26499	iLightBox.prototype = {
26500		showLoader: function() {
26501			var iL = this;
26502			iL.vars.loadRequests += 1;
26503			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
26504				//top: '-30px'
26505				opacity: '1'
26506			}, iL.options.show.speed, 'easeOutCirc');
26507			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
26508				//left: '-30px'
26509				opacity: '1'
26510			}, iL.options.show.speed, 'easeOutCirc');
26511		},
26512
26513		hideLoader: function() {
26514			var iL = this;
26515			iL.vars.loadRequests -= 1;
26516			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
26517			if (iL.options.path.toLowerCase() == "horizontal") {
26518				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
26519					//top: '-192px'
26520					opacity: '0'
26521				}, iL.options.show.speed, 'easeInCirc');
26522			} else {
26523				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
26524					//left: '-192px'
26525					opacity: '0'
26526				}, iL.options.show.speed, 'easeInCirc');
26527			}
26528		},
26529
26530		createUI: function() {
26531			var iL = this;
26532
26533			iL.ui = {
26534				currentElement: iL.vars.holder,
26535				nextElement: iL.vars.nextPhoto,
26536				prevElement: iL.vars.prevPhoto,
26537				currentItem: iL.vars.current,
26538				nextItem: iL.vars.next,
26539				prevItem: iL.vars.prev,
26540				hide: function() {
26541					iL.closeAction();
26542				},
26543				refresh: function() {
26544					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
26545				},
26546				fullscreen: function() {
26547					iL.fullScreenAction();
26548				}
26549			};
26550		},
26551
26552		attachItems: function() {
26553			var iL = this,
26554				itemsObject = new Array(),
26555				items = new Array();
26556
26557			$(iL.selector, iL.context).each(function() {
26558				var t = $(this),
26559					URL = t.attr(iL.options.attr) || null,
26560					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
26561					caption = t.data('caption'),
26562					title = t.data('title'),
26563					type = t.data('type') || getTypeByExtension(URL),
26564					clone = t.data('lbox-clone') || false;
26565
26566				//Uncode addition ##START##
26567				if (type === false) {
26568					return;
26569				}
26570				//Uncode addition ##END##
26571
26572				if (t.data('lbox-clone') != undefined) return;
26573
26574				//Uncode addition ##START##
26575				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
26576					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
26577						URL_i,
26578						URLS_LENGHT = ALBUM_URLS.length;
26579
26580					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
26581						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
26582							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
26583							item_opts = item_opts && eval("({" + item_opts + "})") || {},
26584							items.push({
26585								URL: ALBUM_URLS[URL_i].url,
26586								caption: ALBUM_URLS[URL_i].caption,
26587								title: ALBUM_URLS[URL_i].title,
26588								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
26589								options: item_opts,
26590								clone: clone
26591							});
26592							var newT = t;
26593							newT.attr('href',ALBUM_URLS[URL_i].url);
26594							if (!iL.instant) itemsObject.push(newT);
26595						}
26596					}
26597				} else {
26598				//Uncode addition ##END##
26599					items.push({
26600						URL: URL,
26601						caption: caption,
26602						title: title,
26603						type: type,
26604						options: options,
26605						clone: clone
26606					});
26607				}
26608
26609
26610				if (iL.vars != undefined) iL.vars.total = items.length;
26611
26612				if (!iL.instant) itemsObject.push(t);
26613			});
26614
26615			iL.items = items,
26616				iL.itemsObject = itemsObject;
26617
26618		},
26619
26620		normalizeItems: function() {
26621			var iL = this,
26622				newItems = new Array();
26623
26624			$.each(iL.items, function(key, val) {
26625
26626				if (typeof val == "string") val = {
26627					url: val
26628				};
26629
26630				var URL = val.url || val.URL || null,
26631					options = val.options || {},
26632					caption = val.caption || null,
26633					title = val.title || null,
26634					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
26635					ext = (typeof URL != 'object') ? getExtension(URL) : '';
26636
26637				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
26638				options.videoType = options.videoType || null,
26639				options.skin = options.skin || iL.options.skin,
26640				options.width = options.width || null,
26641				options.height = options.height || null,
26642				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
26643				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
26644				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
26645
26646				if (type == "video") {
26647					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
26648
26649					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
26650					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
26651					options.html5video.preload = options.html5video.preload || "metadata";
26652					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
26653					//UNCODE addition
26654					options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false;
26655				}
26656
26657				if (!options.width || !options.height) {
26658					if (type == "video") options.width = 1280, options.height = 720;
26659					else if (type == "iframe") options.width = '100%', options.height = '90%';
26660					else if (type == "flash") options.width = 1280, options.height = 720;
26661				}
26662
26663				delete val.url;
26664				val.index = key;
26665				val.URL = URL;
26666				val.caption = caption;
26667				val.title = title;
26668				val.type = type;
26669				val.options = options;
26670				val.ext = ext;
26671
26672				newItems.push(val);
26673			});
26674
26675			iL.items = newItems;
26676		},
26677
26678		instantCall: function() {
26679			var iL = this,
26680				key = iL.vars.start;
26681
26682			iL.vars.current = key;
26683			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
26684			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
26685
26686			iL.addContents();
26687			iL.patchEvents();
26688		},
26689
26690		addContents: function() {
26691			var iL = this,
26692				vars = iL.vars,
26693				opts = iL.options,
26694				viewport = getViewport(),
26695				path = opts.path.toLowerCase(),
26696				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
26697					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
26698				}),
26699				needRecognition = recognizingItems.length > 0;
26700
26701			if (opts.mobileOptimizer && !opts.innerToolbar)
26702				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
26703
26704			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
26705
26706			if (opts.linkId)
26707				vars.overlay[0].setAttribute('linkid', opts.linkId);
26708
26709			//Add Toolbar Buttons
26710			if (opts.controls.toolbar) {
26711				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
26712				if (opts.controls.fullscreen)
26713					vars.toolbar.append(vars.fullScreenButton);
26714				if (opts.controls.slideshow)
26715					vars.toolbar.append(vars.innerPlayButton);
26716				if (vars.total > 1)
26717					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
26718			}
26719
26720			//Append elements to body
26721			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
26722
26723			if (!opts.innerToolbar)
26724				vars.BODY.append(vars.toolbar);
26725			if (opts.controls.arrows)
26726				vars.BODY.append(vars.nextButton).append(vars.prevButton);
26727
26728			if (opts.controls.thumbnail && vars.total > 1) {
26729				vars.BODY.append(vars.thumbnails);
26730				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
26731				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
26732				vars.thumbs = true;
26733			}
26734
26735			//Configure loader and arrows
26736			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
26737				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
26738			} : {
26739				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
26740			};
26741			vars.loader.addClass(opts.skin).css(loaderCss);
26742			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
26743			if (path == "horizontal")
26744				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
26745
26746			// Configure arrow buttons
26747			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
26748
26749			if (!opts.infinite) {
26750				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
26751
26752				if (vars.current == 0)
26753					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
26754				if (vars.current >= vars.total - 1)
26755					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
26756			}
26757
26758			if (opts.show.effect) {
26759				vars.overlay.stop().fadeIn(opts.show.speed);
26760				vars.toolbar.stop().fadeIn(opts.show.speed);
26761			} else {
26762				vars.overlay.show();
26763				vars.toolbar.show();
26764			}
26765
26766			var length = recognizingItems.length;
26767			if (needRecognition) {
26768				iL.showLoader();
26769
26770				$.each(recognizingItems, function(key, val) {
26771					var resultFnc = function(result) {
26772							var key = -1,
26773								filter = iL.items.filter(function(e, i, arr) {
26774									if (e.URL == result.url)
26775										key = i;
26776
26777									return e.URL == result.url;
26778								}),
26779								self = iL.items[key];
26780
26781							if (result)
26782								$.extend(true, self, {
26783									URL: result.source,
26784									type: result.type,
26785									recognized: true,
26786									options: {
26787										html5video: result.html5video,
26788										width: (result.type == "image") ? 0 : (result.width || self.width),
26789										height: (result.type == "image") ? 0 : (result.height || self.height),
26790										thumbnail: self.options.thumbnail || result.thumbnail
26791									}
26792								});
26793
26794							length--;
26795
26796							if (length == 0) {
26797								iL.hideLoader();
26798
26799								vars.dontGenerateThumbs = false;
26800								iL.generateThumbnails();
26801
26802								if (opts.show.effect)
26803									setTimeout(function() {
26804										iL.generateBoxes();
26805									}, opts.show.speed);
26806								else
26807									iL.generateBoxes();
26808							}
26809						};
26810
26811					iL.ogpRecognition(this, resultFnc);
26812				});
26813			}
26814			else {
26815				if (opts.show.effect)
26816					setTimeout(function() {
26817						iL.generateBoxes();
26818					}, opts.show.speed);
26819				else
26820					iL.generateBoxes();
26821			}
26822
26823			iL.createUI();
26824
26825			window.iLightBox = {
26826				close: function() {
26827					iL.closeAction();
26828				},
26829				fullscreen: function() {
26830					iL.fullScreenAction();
26831				},
26832				moveNext: function() {
26833					iL.moveTo('next');
26834				},
26835				movePrev: function() {
26836					iL.moveTo('prev');
26837				},
26838				goTo: function(index) {
26839					iL.goTo(index);
26840				},
26841				refresh: function() {
26842					iL.refresh();
26843				},
26844				reposition: function() {
26845					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
26846				},
26847				setOption: function(options) {
26848					iL.setOption(options);
26849				},
26850				destroy: function() {
26851					iL.closeAction();
26852					iL.dispatchItemsEvents();
26853				}
26854			};
26855
26856			if (opts.linkId) {
26857				vars.hashLock = true;
26858				window.location.hash = opts.linkId + '/' + vars.current;
26859				setTimeout(function() {
26860					vars.hashLock = false;
26861				}, 55);
26862			}
26863
26864			if (!opts.slideshow.startPaused) {
26865				iL.resume();
26866				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
26867			}
26868
26869			//Trigger the onOpen callback
26870			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
26871		},
26872
26873		loadContent: function(obj, opt, speed) {
26874			var iL = this,
26875				holder, item;
26876
26877			iL.createUI();
26878
26879			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
26880
26881			if (opt == 'current') {
26882				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
26883				else iL.vars.lockWheel = false;
26884
26885				if (!obj.options.swipe) iL.vars.lockSwipe = true;
26886				else iL.vars.lockSwipe = false;
26887			}
26888
26889			switch (opt) {
26890				case 'current':
26891					holder = iL.vars.holder, item = iL.vars.current;
26892					break;
26893				case 'next':
26894					holder = iL.vars.nextPhoto, item = iL.vars.next;
26895					break;
26896				case 'prev':
26897					holder = iL.vars.prevPhoto, item = iL.vars.prev;
26898					break;
26899			}
26900
26901			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
26902			$('div.ilightbox-inner-toolbar', holder).remove();
26903
26904			if (obj.title || iL.options.innerToolbar) {
26905				var innerToolbar = iL.vars.innerToolbar.clone();
26906				if (obj.title && iL.options.show.title) {
26907					var title = iL.vars.title.clone();
26908					title.empty().html(obj.title);
26909					innerToolbar.append(title);
26910				}
26911				if (iL.options.innerToolbar) {
26912					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
26913				}
26914				holder.prepend(innerToolbar);
26915			}
26916
26917			//console.warn('loadContent', arguments);
26918
26919			iL.loadSwitcher(obj, holder, item, opt);
26920		},
26921
26922		loadSwitcher: function(obj, holder, item, opt) {
26923			var iL = this,
26924				opts = iL.options,
26925				api = {
26926					element: holder,
26927					position: item
26928				};
26929
26930			switch (obj.type) {
26931				case 'image':
26932					//Trigger the onBeforeLoad callback
26933					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
26934					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
26935
26936					iL.loadImage(obj.URL, function(img) {
26937						//Trigger the onAfterLoad callback
26938						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
26939						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
26940
26941						var width = (img) ? img.width : 400,
26942							height = (img) ? img.height : 200;
26943
26944						holder.data({
26945							naturalWidth: width,
26946							naturalHeight: height
26947						});
26948
26949						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
26950
26951						//Trigger the onRender callback
26952						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
26953						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
26954
26955						iL.configureHolder(obj, opt, holder);
26956					});
26957
26958					break;
26959
26960				case 'video':
26961					holder.data({
26962						naturalWidth: obj.options.width,
26963						naturalHeight: obj.options.height
26964					});
26965
26966					if (opt === 'current') {
26967						iL.addContent(holder, obj);
26968
26969						//Trigger the onRender callback
26970						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
26971						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
26972					} else {
26973						$('div.ilightbox-container', holder).empty();
26974					}
26975
26976					iL.configureHolder(obj, opt, holder);
26977
26978					break;
26979
26980				case 'iframe':
26981					//iL.showLoader();
26982					holder.data({
26983						naturalWidth: obj.options.width,
26984						naturalHeight: obj.options.height
26985					});
26986
26987					iL.configureHolder(obj, opt, holder);
26988
26989					if (opt === 'current') {
26990						var el = iL.addContent(holder, obj);
26991
26992						//Trigger the onRender callback
26993						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
26994						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
26995
26996						//Trigger the onBeforeLoad callback
26997						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
26998						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
26999
27000						el.bind('load', function() {
27001							//Trigger the onAfterLoad callback
27002							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
27003							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
27004
27005							//iL.hideLoader();
27006							el.unbind('load');
27007						});
27008					} else {
27009						$('div.ilightbox-container', holder).empty();
27010					}
27011
27012					break;
27013
27014				case 'inline':
27015					var el = $(obj.URL),
27016						content = iL.addContent(holder, obj),
27017						images = findImageInElement(holder);
27018
27019					holder.data({
27020						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
27021						naturalHeight: (iL.items[item].options.height || el.outerHeight())
27022					});
27023					content.children().eq(0).show();
27024
27025					//Trigger the onRender callback
27026					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
27027					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
27028
27029					//Trigger the onBeforeLoad callback
27030					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
27031					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
27032
27033					iL.loadImage(images, function() {
27034						//Trigger the onAfterLoad callback
27035						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
27036						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
27037
27038						iL.configureHolder(obj, opt, holder);
27039					});
27040
27041					break;
27042
27043				case 'flash':
27044					var el = iL.addContent(holder, obj);
27045
27046					holder.data({
27047						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
27048						naturalHeight: (iL.items[item].options.height || el.outerHeight())
27049					});
27050
27051					//Trigger the onRender callback
27052					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
27053					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
27054
27055					iL.configureHolder(obj, opt, holder);
27056
27057					break;
27058
27059				case 'ajax':
27060					var ajax = obj.options.ajax || {};
27061					//Trigger the onBeforeLoad callback
27062					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
27063					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
27064
27065					iL.showLoader();
27066					$.ajax({
27067						url: obj.URL || opts.ajaxSetup.url,
27068						data: ajax.data || null,
27069						dataType: ajax.dataType || "html",
27070						type: ajax.type || opts.ajaxSetup.type,
27071						cache: ajax.cache || opts.ajaxSetup.cache,
27072						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
27073						global: ajax.global || opts.ajaxSetup.global,
27074						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
27075						username: ajax.username || opts.ajaxSetup.username,
27076						password: ajax.password || opts.ajaxSetup.password,
27077						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
27078						complete: ajax.complete || opts.ajaxSetup.complete,
27079						success: function(data, textStatus, jqXHR) {
27080							iL.hideLoader();
27081
27082							var el = $(data),
27083								container = $('div.ilightbox-container', holder),
27084								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
27085								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
27086								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
27087									'overflow': 'hidden'
27088								} : {};
27089
27090							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
27091							holder.show().data({
27092								naturalWidth: (elWidth || container.outerWidth()),
27093								naturalHeight: (elHeight || container.outerHeight())
27094							}).hide();
27095
27096							//Trigger the onRender callback
27097							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
27098							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
27099
27100							var images = findImageInElement(holder);
27101							iL.loadImage(images, function() {
27102								//Trigger the onAfterLoad callback
27103								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
27104								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
27105
27106								iL.configureHolder(obj, opt, holder);
27107							});
27108
27109							opts.ajaxSetup.success(data, textStatus, jqXHR);
27110							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
27111						},
27112						error: function(jqXHR, textStatus, errorThrown) {
27113							//Trigger the onAfterLoad callback
27114							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
27115							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
27116
27117							iL.hideLoader();
27118							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
27119							iL.configureHolder(obj, opt, holder);
27120
27121							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
27122							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
27123						}
27124					});
27125
27126					break;
27127
27128				case 'html':
27129					var object = obj.URL,
27130						el
27131					container = $('div.ilightbox-container', holder);
27132
27133					if (object[0].nodeName) el = object.clone();
27134					else {
27135						var dom = $(object);
27136						if (dom.selector) el = $('<div>' + dom + '</div>');
27137						else el = dom;
27138					}
27139
27140					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
27141						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
27142
27143					iL.addContent(holder, obj);
27144
27145					el.appendTo(document.documentElement).hide();
27146
27147					//Trigger the onRender callback
27148					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
27149					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
27150
27151					var images = findImageInElement(holder);
27152
27153					//Trigger the onBeforeLoad callback
27154					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
27155					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
27156
27157					iL.loadImage(images, function() {
27158						//Trigger the onAfterLoad callback
27159						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
27160						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
27161
27162						holder.show().data({
27163							naturalWidth: (elWidth || container.outerWidth()),
27164							naturalHeight: (elHeight || container.outerHeight())
27165						}).hide();
27166						el.remove();
27167
27168						iL.configureHolder(obj, opt, holder);
27169					});
27170
27171					break;
27172			}
27173		},
27174
27175		configureHolder: function(obj, opt, holder) {
27176			var iL = this,
27177				vars = iL.vars,
27178				opts = iL.options;
27179
27180			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
27181
27182			if (opt == "current")
27183				var item = vars.current;
27184			else if (opt == "next")
27185				var opacity = opts.styles.nextOpacity,
27186					item = vars.next;
27187			else
27188				var opacity = opts.styles.prevOpacity,
27189					item = vars.prev;
27190
27191			var api = {
27192				element: holder,
27193				position: item
27194			};
27195
27196			iL.items[item].options.width = iL.items[item].options.width || 0,
27197			iL.items[item].options.height = iL.items[item].options.height || 0;
27198
27199			if (opt == "current") {
27200				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
27201					holder.css(transform, '');
27202					if (obj.caption) {
27203						iL.setCaption(obj, holder);
27204						var caption = $('div.ilightbox-caption', holder),
27205							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
27206						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
27206Speed);
27207					}
27208
27209					var social = obj.options.social;
27210					if (social) {
27211						iL.setSocial(social, obj.URL, holder);
27212						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
27213					}
27214
27215					//Generate thumbnails
27216					iL.generateThumbnails();
27217
27218					//Trigger the onShow callback
27219					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
27220					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
27221				});
27222				else {
27223					holder.show();
27224
27225					//Generate thumbnails
27226					iL.generateThumbnails();
27227
27228					//Trigger the onShow callback
27229					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
27230					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
27231				}
27232			} else {
27233				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
27234					if (opt == "next") vars.nextLock = false;
27235					else vars.prevLock = false;
27236
27237					//Generate thumbnails
27238					iL.generateThumbnails();
27239
27240					//Trigger the onShow callback
27241					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
27242					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
27243				});
27244				else {
27245					holder.css({
27246						opacity: opacity
27247					}).show();
27248					if (opt == "next") vars.nextLock = false;
27249					else vars.prevLock = false;
27250
27251					//Generate thumbnails
27252					iL.generateThumbnails();
27253
27254					//Trigger the onShow callback
27255					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
27256					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
27257				}
27258			}
27259
27260			setTimeout(function() {
27261				iL.repositionPhoto();
27262			}, 0);
27263		},
27264
27265		generateBoxes: function() {
27266			var iL = this,
27267				vars = iL.vars,
27268				opts = iL.options;
27269
27270			if (opts.infinite && vars.total >= 3) {
27271				if (vars.current == vars.total - 1) vars.next = 0;
27272				if (vars.current == 0) vars.prev = vars.total - 1;
27273			} else opts.infinite = false;
27274
27275			//UNCODE addition
27276			if ( typeof iL.items[vars.current] == 'undefined' )
27277				vars.current = 0;
27278
27279			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
27280
27281			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
27282			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
27283		},
27284
27285		generateThumbnails: function() {
27286			var iL = this,
27287				vars = iL.vars,
27288				opts = iL.options,
27289				timeOut = null;
27290
27291			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
27292				var thumbnails = vars.thumbnails,
27293					container = $('div.ilightbox-thumbnails-container', thumbnails),
27294					grid = $('div.ilightbox-thumbnails-grid', container),
27295					i = 0;
27296
27297				grid.removeAttr('style').empty();
27298
27299				$.each(iL.items, function(key, val) {
27300					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
27301						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
27302						thumb = val.options.thumbnail,
27303						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
27304						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
27305
27306					thumbnail.css({
27307						opacity: 0
27308					}).addClass(isActive);
27309
27310					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
27311						icon.addClass('ilightbox-thumbnail-video');
27312						thumbnail.append(icon);
27313					} else if (val.options.icon) {
27314						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
27315						thumbnail.append(icon);
27316					}
27317
27318					if (thumb) iL.loadImage(thumb, function(img) {
27319						i++;
27320						if (img) thumbnail.data({
27321							naturalWidth: img.width,
27322							naturalHeight: img.height
27323						}).append('<img src="' + thumb + '" border="0" />');
27324						else thumbnail.data({
27325							naturalWidth: opts.thumbnails.maxWidth,
27326							naturalHeight: opts.thumbnails.maxHeight
27327						});
27328
27329						clearTimeout(timeOut);
27330						timeOut = setTimeout(function() {
27331							iL.positionThumbnails(thumbnails, container, grid);
27332						}, 20);
27333						setTimeout(function() {
27334							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
27335						}, i * 20);
27336					});
27337
27338					grid.append(thumbnail);
27339				});
27340				iL.vars.dontGenerateThumbs = true;
27341			}
27342		},
27343
27344		positionThumbnails: function(thumbnails, container, grid) {
27345			var iL = this,
27346				vars = iL.vars,
27347				opts = iL.options,
27348				viewport = getViewport(),
27349				path = opts.path.toLowerCase();
27350
27351			if (!thumbnails) thumbnails = vars.thumbnails;
27352			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
27353			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
27354
27355			var thumbs = $('.ilightbox-thumbnail', grid),
27356				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
27357				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
27358				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
27359				gridHeight = (path == 'horizontal') ? heightAvail : 0,
27360				active = $('.ilightbox-active', grid),
27361				gridCss = {},
27362				css = {};
27363
27364			if (arguments.length < 3) {
27365				thumbs.css({
27366					opacity: opts.thumbnails.normalOpacity
27367				});
27368				active.css({
27369					opacity: opts.thumbnails.activeOpacity
27370				});
27371			}
27372
27373			thumbs.each(function(i) {
27374				var t = $(this),
27375					data = t.data(),
27376					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
27377				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
27378				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
27379
27380				t.css({
27381					width: dims.width,
27382					height: dims.height
27383				});
27384				if (path == 'horizontal') t.css({
27385					'float': 'left'
27386				});
27387
27388				(path == 'horizontal') ? (
27389					gridWidth += t.outerWidth()
27390				) : (
27391					gridHeight += t.outerHeight()
27392				);
27393			});
27394
27395			gridCss = {
27396				width: gridWidth,
27397				height: gridHeight
27398			};
27399
27400			grid.css(gridCss);
27401
27402			gridCss = {};
27403
27404			var gridOffset = grid.offset(),
27405				activeOffset = (active.length) ? active.offset() : {
27406					top: parseInt(heightAvail / 2),
27407					left: parseInt(widthAvail / 2)
27408				};
27409
27410			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
27411				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
27412				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
27413				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
27414
27415			(path == 'horizontal') ? (
27416				gridCss.top = 0,
27417				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
27418			) : (
27419				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
27420				gridCss.left = 0
27421			);
27422
27423			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
27424			else grid.css(gridCss);
27425		},
27426
27427		loadImage: function(image, callback) {
27428			if (!$.isArray(image)) image = [image];
27429
27430			var iL = this,
27431				length = image.length;
27432
27433			if (length > 0) {
27434				iL.showLoader();
27435				$.each(image, function(index, value) {
27436					var img = new Image();
27437					img.onload = function() {
27438						length -= 1;
27439						if (length == 0) {
27440							iL.hideLoader();
27441							callback(img);
27442						}
27443					};
27444					img.onerror = img.onabort = function() {
27445						length -= 1;
27446						if (length == 0) {
27447							iL.hideLoader();
27448							callback(false);
27449						}
27450					};
27451					img.src = image[index];
27452				});
27453			} else callback(false);
27454		},
27455
27456		patchItemsEvents: function() {
27457			var iL = this,
27458				vars = iL.vars,
27459				clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL",
27460				vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL";
27461
27462			if (iL.context && iL.selector) {
27463				var $items = $(iL.selector, iL.context);
27464
27465				$(iL.context).on(clickEvent, iL.selector, function() {
27466					var $this = $(this),
27467						//UNCODE addition
27468						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
27469					if (UNCODE.isMobile) {
27470						var isCarousel = $this.closest('.owl-carousel');
27471						if (isCarousel.length) {
27472							if (isCarousel.hasClass('owl-translating')) return false;
27473						}
27474					}
27475
27476					vars.current = key;
27477					vars.next = iL.items[key + 1] ? key + 1 : null;
27478					vars.prev = iL.items[key - 1] ? key - 1 : null;
27479
27480					//UNCODE addition
27481					if ( vars.BODY.hasClass('fp-slide-scrolling') )
27482						return false;
27483
27484					iL.addContents();
27485					iL.patchEvents();
27486
27487					return false;
27488				}).on(vEvent, iL.selector, function() {
27489					return false;
27490				});
27491			} else
27492				$.each(iL.itemsObject, function(key, val) {
27493					val.on(clickEvent, function() {
27494						vars.current = key;
27495						vars.next = iL.items[key + 1] ? key + 1 : null;
27496						vars.prev = iL.items[key - 1] ? key - 1 : null;
27497
27498						iL.addContents();
27499						iL.patchEvents();
27500
27501						return false;
27502					}).on(vEvent, function() {
27503						return false;
27504					});
27505				});
27506		},
27507
27508		dispatchItemsEvents: function() {
27509			var iL = this,
27510				vars = iL.vars,
27511				opts = iL.options;
27512
27513			if (iL.context && iL.selector)
27514				$(iL.context).off('.iL', iL.selector);
27515			else
27516				$.each(iL.itemsObject, function(key, val) {
27517					val.off('.iL');
27518				});
27519		},
27520
27521		refresh: function() {
27522			var iL = this;
27523
27524			iL.dispatchItemsEvents();
27525			iL.attachItems();
27526			iL.normalizeItems();
27527			iL.patchItemsEvents();
27528		},
27529
27530		patchEvents: function() {
27531			var iL = this,
27532				vars = iL.vars,
27533				opts = iL.options,
27534				path = opts.path.toLowerCase(),
27535				holders = $('.ilightbox-holder'),
27536				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
27537				durationThreshold = 1000,
27538				horizontalDistanceThreshold =
27539				verticalDistanceThreshold = 100,
27540				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
27541
27542			$win.bind('resize.iLightBox', function() {
27543				var viewport = getViewport();
27544
27545				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
27546				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
27547
27548				iL.repositionPhoto(null);
27549				if (supportTouch) {
27550					clearTimeout(vars.setTime);
27551					vars.setTime = setTimeout(function() {
27552						var scrollTop = getScrollXY().y;
27553						window.scrollTo(0, scrollTop - 30);
27554						window.scrollTo(0, scrollTop + 30);
27555						window.scrollTo(0, scrollTop);
27556					}, 2000);
27557				}
27558				if (vars.thumbs) iL.positionThumbnails();
27559			}).bind('keydown.iLightBox', function(event) {
27560				if (opts.controls.keyboard) {
27561					switch (event.keyCode) {
27562						case 13:
27563							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
27564							break;
27565						case 27:
27566							if (opts.keyboard.esc) iL.closeAction();
27567							break;
27568						case 37:
27569							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
27570							break;
27571						case 38:
27572							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
27573							break;
27574						case 39:
27575							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
27576							break;
27577						case 40:
27578							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
27579							break;
27580					}
27581				}
27582			});
27583
27584			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
27585				iL.doFullscreen();
27586			});
27587
27588			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
27589					return arr.lastIndexOf(e) === i;
27590				}),
27591				holderEvents = "";
27592
27593			$.each(holderEventsArr, function(key, val) {
27594				if (key != 0) holderEvents += ' ';
27595				holderEvents += val;
27596			});
27597
27598			$doc.on(clickEvent, '.ilightbox-overlay', function() {
27599				if (opts.overlay.blur) iL.closeAction();
27600			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
27601				iL.moveTo('next');
27602			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
27603				iL.moveTo('prev');
27604			}).on(clickEvent, '.ilightbox-thumbnail', function() {
27605				var t = $(this),
27606					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
27607					index = thumbs.index(t);
27608
27609				if (index != vars.current) iL.goTo(index);
27610			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
27611				var caption = $('div.ilightbox-caption', vars.holder),
27612					social = $('div.ilightbox-social', vars.holder),
27613					fadeSpeed = opts.effects.fadeSpeed;
27614
27615				if (vars.nextLock || vars.prevLock) {
27616					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
27617					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
27618
27619					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
27620					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
27621				} else {
27622					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
27623					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
27624
27625					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
27626					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
27627				}
27628			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
27629				if (e.type == 'mouseenter') vars.lockWheel = true;
27630				else vars.lockWheel = false;
27631			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
27632				var t = $(this);
27633
27634				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
27635				else if (t.hasClass('ilightbox-play')) {
27636					iL.resume();
27637					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
27638				} else if (t.hasClass('ilightbox-pause')) {
27639					iL.pause();
27640					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
27641				} else iL.closeAction();
27642			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
27643				// prevent scrolling
27644				e.preventDefault();
27645			});
27646
27647			function mouseMoveHandler(e) {
27648				if (!vars.isMobile) {
27649					if (!vars.mouseID) {
27650						vars.hideableElements.show();
27651					}
27652
27653					vars.mouseID = clearTimeout(vars.mouseID);
27654
27655					if (buttonsArray.indexOf(e.target) === -1)
27656						vars.mouseID = setTimeout(function() {
27657							vars.hideableElements.hide();
27658							vars.mouseID = clearTimeout(vars.mouseID);
27659						}, 3000);
27660				}
27661			}
27662
27663			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
27664
27665			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
27666				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
27667				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
27668			});
27669
27670			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'),
27671				delay = false;
27672
27673			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
27674				event.preventDefault();
27675				if (delay) return;
27676				delay = true;
27677				if (!vars.lockWheel) {
27678					event.preventDefault();
27679					if (delta < 0) {
27680						iL.moveTo('next');
27681					} else if (delta > 0) {
27682						iL.moveTo('prev');
27683					}
27684				}
27685				setTimeout(function(){
27686					delay = false;
27687				}, 2000);
27688			});
27689
27690			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
27691				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
27692
27693				vars.BODY.addClass('ilightbox-closedhand');
27694
27695				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
27696					scrollTop = $doc.scrollTop(),
27697					scrollLeft = $doc.scrollLeft(),
27698					offsets = [
27699						holders.eq(0).offset(),
27700						holders.eq(1).offset(),
27701						holders.eq(2).offset()
27702					],
27703					offSet = [{
27704						top: offsets[0].top - scrollTop,
27705						left: offsets[0].left - scrollLeft
27706					}, {
27707						top: offsets[1].top - scrollTop,
27708						left: offsets[1].left - scrollLeft
27709					}, {
27710						top: offsets[2].top - scrollTop,
27711						left: offsets[2].left - scrollLeft
27712					}],
27713					start = {
27714						time: (new Date()).getTime(),
27715						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
27716					},
27717					stop;
27718
27719				function moveEachHandler(i) {
27720					var t = $(this),
27721						offset = offSet[i],
27722						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
27723
27724					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
27725				}
27726
27727				function moveHandler(event) {
27728
27729					if (!start) return;
27730
27731					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
27732
27733					stop = {
27734						time: (new Date()).getTime(),
27735						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
27736					};
27737
27738					holders.each(moveEachHandler);
27739
27740					// prevent scrolling
27741					event.preventDefault();
27742				}
27743
27744				function repositionHolders() {
27745					holders.each(function() {
27746						var t = $(this),
27747							offset = t.data('offset') || {
27748								top: t.offset().top - scrollTop,
27749								left: t.offset().left - scrollLeft
27750							},
27751							top = offset.top,
27752							left = offset.left;
27753
27754						t.css(transform, gpuAcceleration).stop().animate({
27755							top: top,
27756							left: left
27757						}, 500, 'easeOutCirc', function() {
27758							t.css(transform, '');
27759						});
27760					});
27761				}
27762
27763				holders.bind(touchMoveEvent, moveHandler);
27764				$doc.one(touchStopEvent, function(event) {
27765					holders.unbind(touchMoveEvent, moveHandler);
27766
27767					vars.BODY.removeClass('ilightbox-closedhand');
27768
27769					if (start && stop) {
27770						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
27771							if (start.coords[0] > stop.coords[0]) {
27772								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
27773								else {
27774									vars.isSwipe = true;
27775									iL.moveTo('next');
27776								}
27777							} else {
27778								if (vars.current == 0 && !opts.infinite) repositionHolders();
27779								else {
27780									vars.isSwipe = true;
27781									iL.moveTo('prev');
27782								}
27783							}
27784						} else if (path == "vertical" && stop.time - start.time < durationThreshold && abs(start.coords[1] - stop.coords[1]) > horizontalDistanceThreshold && abs(start.coords[0] - stop.coords[0]) < verticalDistanceThreshold) {
27785							if (start.coords[1] > stop.coords[1]) {
27786								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
27787								else {
27788									vars.isSwipe = true;
27789									iL.moveTo('next');
27790								}
27791							} else {
27792								if (vars.current == 0 && !opts.infinite) repositionHolders();
27793								else {
27794									vars.isSwipe = true;
27795									iL.moveTo('prev');
27796								}
27797							}
27798						} else repositionHolders();
27799					}
27800					start = stop = undefined;
27801				});
27802			});
27803
27804		},
27805
27806		goTo: function(index) {
27807			var iL = this,
27808				vars = iL.vars,
27809				opts = iL.options,
27810				diff = (index - vars.current);
27811
27812			if (opts.infinite) {
27813				if (index == vars.total - 1 && vars.current == 0) diff = -1;
27814				if (vars.current == vars.total - 1 && index == 0) diff = 1;
27815			}
27816
27817			if (diff == 1) iL.moveTo('next');
27818			else if (diff == -1) iL.moveTo('prev');
27819			else {
27820
27821				if (vars.nextLock || vars.prevLock) return false;
27822
27823				//Trigger the onBeforeChange callback
27824				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
27825
27826				if (opts.linkId) {
27827					vars.hashLock = true;
27828					window.location.hash = opts.linkId + '/' + index;
27829				}
27830
27831				if (iL.items[index]) {
27832					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
27833					else iL.vars.lockWheel = false;
27834
27835					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
27836					else vars.lockSwipe = false;
27837				}
27838
27839				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
27840					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
27841				});
27842
27843				vars.current = index;
27844				vars.next = index + 1;
27845				vars.prev = index - 1;
27846
27847				iL.createUI();
27848
27849				setTimeout(function() {
27850					iL.generateBoxes();
27851				}, opts.effects.loadedFadeSpeed + 50);
27852
27853				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
27854				iL.positionThumbnails();
27855
27856				if (opts.linkId) setTimeout(function() {
27857					vars.hashLock = false;
27858				}, 55);
27859
27860				// Configure arrow buttons
27861				if (!opts.infinite) {
27862					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
27863
27864					if (vars.current == 0) {
27865						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
27866					}
27867					if (vars.current >= vars.total - 1) {
27868						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
27869					}
27870				}
27871
27872				// Reset next cycle timeout
27873				iL.resetCycle();
27874
27875				//Trigger the onAfterChange callback
27876				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
27877			}
27878		},
27879
27880		moveTo: function(side) {
27881			var iL = this,
27882				vars = iL.vars,
27883				opts = iL.options,
27884				path = opts.path.toLowerCase(),
27885				viewport = getViewport(),
27886				switchSpeed = opts.effects.switchSpeed;
27887
27888			if (vars.nextLock || vars.prevLock) return false;
27889			else {
27890
27891				var item = (side == "next") ? vars.next : vars.prev;
27892
27893				if (opts.linkId) {
27894					vars.hashLock = true;
27895					window.location.hash = opts.linkId + '/' + item;
27896				}
27897
27898				if (side == "next") {
27899					if (!iL.items[item]) return false;
27900					var firstHolder = vars.nextPhoto,
27901						secondHolder = vars.holder,
27902						lastHolder = vars.prevPhoto,
27903						firstClass = 'ilightbox-prev',
27904						secondClass = 'ilightbox-next';
27905				} else if (side == "prev") {
27906					if (!iL.items[item]) return false;
27907					var firstHolder = vars.prevPhoto,
27908						secondHolder = vars.holder,
27909						lastHolder = vars.nextPhoto,
27910						firstClass = 'ilightbox-next',
27911						secondClass = 'ilightbox-prev';
27912				}
27913
27914				//Trigger the onBeforeChange callback
27915				if (typeof opts.callback.onBeforeChange == 'function')
27916					opts.callback.onBeforeChange.call(iL, iL.ui);
27917
27918				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
27919
27920				var captionFirst = $('div.ilightbox-caption', secondHolder),
27921					socialFirst = $('div.ilightbox-social', secondHolder);
27922
27923				if (captionFirst.length)
27924					captionFirst.stop().fadeOut(switchSpeed, function() {
27925						$(this).remove();
27926					});
27927				if (socialFirst.length)
27928					socialFirst.stop().fadeOut(switchSpeed, function() {
27929						$(this).remove();
27930					});
27931
27932				if (iL.items[item].caption) {
27933					iL.setCaption(iL.items[item], firstHolder);
27934					var caption = $('div.ilightbox-caption', firstHolder),
27935						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
27936					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
27937				}
27938
27939				var social = iL.items[item].options.social;
27940				if (social) {
27941					iL.setSocial(social, iL.items[item].URL, firstHolder);
27942					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
27943				}
27944
27945				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
27946					val.removeClass('ilightbox-next ilightbox-prev');
27947				});
27948
27949				var firstOffset = firstHolder.data('offset'),
27950					winW = (viewport.width - (opts.styles.pageOffsetX)),
27951					winH = (viewport.height - (opts.styles.pageOffsetY)),
27952					width = firstOffset.newDims.width,
27953					height = firstOffset.newDims.height,
27954					thumbsOffset = firstOffset.thumbsOffset,
27955					diff = firstOffset.diff,
27956					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
27957					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
27958
27959				var secondOffset = secondHolder.data('offset'),
27960					object = secondOffset.object;
27961
27962				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
27963					var objRatio = width / height;
27964					height = height - vars.captionHeight;
27965					width = height * objRatio;
27966					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
27967					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
27968				}*/
27969
27970				firstHolder.show().css(transform, gpuAcceleration).animate({
27971					top: top,
27972					left: left,
27973					opacity: 1
27974				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
27975					firstHolder.css(transform, '');
27976				});
27977
27978				$('div.ilightbox-container', firstHolder).animate({
27979					width: width,
27980					height: height
27981				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
27982
27983				diff = secondOffset.diff;
27984
27985				width = secondOffset.newDims.width,
27986					height = secondOffset.newDims.height;
27987
27988				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
27989					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
27990					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
27991
27992				if (side == 'prev')
27993					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
27994				else {
27995					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
27996					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
27997				}
27998
27999				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
28000					var objRatio = width / height;
28001					height = height - vars.captionHeight;
28002					width = height * objRatio;
28003					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
28004				}*/
28005
28006				$('div.ilightbox-container', secondHolder).animate({
28007					width: width,
28008					height: height
28009				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
28010
28011				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
28012					top: top,
28013					left: left,
28014					opacity: opts.styles.prevOpacity,
28015				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
28016					secondHolder.css(transform, '');
28017
28018					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
28019					iL.positionThumbnails();
28020
28021					if (iL.items[item]) {
28022						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
28023						else vars.lockWheel = false;
28024
28025						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
28026						else vars.lockSwipe = false;
28027					}
28028
28029					vars.isSwipe = false;
28030
28031					// Remove iframe & video from previous slide
28032					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
28033						$('div.ilightbox-container', secondHolder).empty();
28034					}
28035
28036					if (side == "next") {
28037						vars.nextPhoto = lastHolder,
28038							vars.prevPhoto = secondHolder,
28039							vars.holder = firstHolder;
28040
28041						vars.nextPhoto.hide();
28042
28043						vars.next = vars.next + 1,
28044							vars.prev = vars.current,
28045							vars.current = vars.current + 1;
28046
28047						if (opts.infinite) {
28048							if (vars.current > vars.total - 1) vars.current = 0;
28049							if (vars.current == vars.total - 1) vars.next = 0;
28050							if (vars.current == 0) vars.prev = vars.total - 1;
28051						}
28052
28053						iL.createUI();
28054
28055						if (!iL.items[vars.next])
28056							vars.nextLock = false;
28057						else
28058							iL.loadContent(iL.items[vars.next], 'next');
28059					} else {
28060						vars.prevPhoto = lastHolder;
28061						vars.nextPhoto = secondHolder;
28062						vars.holder = firstHolder;
28063
28064						vars.prevPhoto.hide();
28065
28066						vars.next = vars.current;
28067						vars.current = vars.prev;
28068						vars.prev = vars.current - 1;
28069
28070						if (opts.infinite) {
28071							if (vars.current == vars.total - 1) vars.next = 0;
28072							if (vars.current == 0) vars.prev = vars.total - 1;
28073						}
28074
28075						iL.createUI();
28076
28077						if (!iL.items[vars.prev])
28078							vars.prevLock = false;
28079						else
28080							iL.loadContent(iL.items[vars.prev], 'prev');
28081					}
28082
28083					// Add iframe & video content for current slide
28084					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
28085						iL.loadContent(iL.items[vars.current], 'current');
28086					}
28087
28088					if (opts.linkId) setTimeout(function() {
28089						vars.hashLock = false;
28090					}, 55);
28091
28092					// Configure arrow buttons
28093					if (!opts.infinite) {
28094						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
28095
28096						if (vars.current == 0)
28097							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
28098						if (vars.current >= vars.total - 1)
28099							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
28100					}
28101
28102					iL.repositionPhoto();
28103
28104					// Reset next cycle timeout
28105					iL.resetCycle();
28106
28107					//Trigger the onAfterChange callback
28108					if (typeof opts.callback.onAfterChange == 'function')
28109						opts.callback.onAfterChange.call(iL, iL.ui);
28110				});
28111
28112				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
28113					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
28114
28115				lastHolder.css(transform, gpuAcceleration).animate({
28116					top: top,
28117					left: left,
28118					opacity: opts.styles.nextOpacity
28119				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
28120					lastHolder.css(transform, '');
28121				}).addClass(secondClass);
28122			}
28123		},
28124
28125		setCaption: function(obj, target) {
28126			var iL = this,
28127				caption = $('<div class="ilightbox-caption"></div>');
28128
28129			if (obj.caption) {
28130				caption.html(obj.caption);
28131				$('div.ilightbox-container', target).append(caption);
28132			}
28133		},
28134
28135		normalizeSocial: function(obj, url) {
28136			var iL = this,
28137				vars = iL.vars,
28138				opts = iL.options,
28139				baseURL = window.location.href;
28140
28141			$.each(obj, function(key, value) {
28142				if (!value)
28143					return true;
28144
28145				var item = key.toLowerCase(),
28146					source, text;
28147
28148				switch (item) {
28149					case 'facebook':
28150						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
28151							text = "Share on Facebook";
28152						break;
28153					case 'twitter':
28154						source = "http://twitter.com/home?status={URL}",
28155							text = "Share on Twitter";
28156						break;
28157					case 'digg':
28158						source = "http://digg.com/submit?phase=2&url={URL}",
28159							text = "Share on Digg";
28160						break;
28161					case 'reddit':
28162						source = "http://reddit.com/submit?url={URL}",
28163							text = "Share on reddit";
28164						break;
28165				}
28166
28167				obj[key] = {
28168					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
28169					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
28170					text: value.text || text || "Share on " + key,
28171					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
28172					height: value.height || 360
28173				};
28174
28175			});
28176
28177			return obj;
28178		},
28179
28180		setSocial: function(obj, url, target) {
28181			var iL = this,
28182				socialBar = $('<div class="ilightbox-social"></div>'),
28183				buttons = '<ul>';
28184
28185			obj = iL.normalizeSocial(obj, url);
28186
28187			$.each(obj, function(key, value) {
28188				var item = key.toLowerCase(),
28189					source = value.source.replace(/\{URL\}/g, encodeURIComponent(value.URL).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+'));
28190				buttons += '<li class="' + key + '"><a href="' + source + '" onclick="javascript:window.open(this.href' + ((value.width <= 0 || value.height <= 0) ? '' : ', \'\', \'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=' + value.height + ',width=' + value.width + ',left=40,top=40\'') + ');return false;" title="' + value.text + '" target="_blank"></a></li>';
28191			});
28192
28193			buttons += '</ul>';
28194
28195			socialBar.html(buttons);
28196			$('div.ilightbox-container', target).append(socialBar);
28197		},
28198
28199		fullScreenAction: function() {
28200			var iL = this,
28201				vars = iL.vars;
28202
28203			if (fullScreenApi.supportsFullScreen) {
28204				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
28205				else fullScreenApi.requestFullScreen(document.documentElement);
28206			} else {
28207				iL.doFullscreen();
28208			}
28209		},
28210
28211		doFullscreen: function() {
28212			var iL = this,
28213				vars = iL.vars,
28214				viewport = getViewport(),
28215				opts = iL.options;
28216
28217			if (opts.fullAlone) {
28218				var currentHolder = vars.holder,
28219					current = iL.items[vars.current],
28220					windowWidth = viewport.width,
28221					windowHeight = viewport.height,
28222					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
28223					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
28224
28225				if (!vars.isInFullScreen) {
28226					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
28227					vars.overlay.css({
28228						opacity: 1
28229					});
28230
28231					$.each(hideElements, function(i, element) {
28232						element.hide();
28233					});
28234
28235					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
28236
28237					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
28238						naturalWidthOld: currentHolder.data('naturalWidth'),
28239						naturalHeightOld: currentHolder.data('naturalHeight'),
28240						naturalWidth: windowWidth,
28241						naturalHeight: windowHeight
28242					});
28243					else {
28244						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
28245							newWidth = windowWidth,
28246							newHeight = windowHeight,
28247							width = currentHolder.data('naturalWidth'),
28248							height = currentHolder.data('naturalHeight');
28249
28250						if (viewport.toLowerCase() == 'fill') {
28251							newHeight = (newWidth / width) * height;
28252
28253							if (newHeight < windowHeight) {
28254								newWidth = (windowHeight / height) * width,
28255									newHeight = windowHeight;
28256							}
28257						} else if (viewport.toLowerCase() == 'fit') {
28258							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
28259
28260							newWidth = dims.width,
28261								newHeight = dims.height;
28262						} else if (viewport.toLowerCase() == 'stretch') {
28263							newWidth = newWidth,
28264								newHeight = newHeight;
28265						} else {
28266							var scale = (width > newWidth || height > newHeight) ? true : false,
28267								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
28268							newWidth = dims.width,
28269								newHeight = dims.height;
28270						}
28271
28272						currentHolder.data({
28273							naturalWidthOld: currentHolder.data('naturalWidth'),
28274							naturalHeightOld: currentHolder.data('naturalHeight'),
28275							naturalWidth: newWidth,
28276							naturalHeight: newHeight
28277						});
28278					}
28279
28280					$.each(elements, function(key, val) {
28281						val.addClass('ilightbox-fullscreen');
28282					});
28283
28284					//Trigger the onEnterFullScreen callback
28285					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
28286				} else {
28287					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
28288					vars.overlay.css({
28289						opacity: iL.options.overlay.opacity
28290					});
28291
28292					$.each(hideElements, function(i, element) {
28293						element.show();
28294					});
28295
28296					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
28297
28298					currentHolder.data({
28299						naturalWidth: currentHolder.data('naturalWidthOld'),
28300						naturalHeight: currentHolder.data('naturalHeightOld'),
28301						naturalWidthOld: null,
28302						naturalHeightOld: null
28303					});
28304
28305					$.each(elements, function(key, val) {
28306						val.removeClass('ilightbox-fullscreen');
28307					});
28308
28309					//Trigger the onExitFullScreen callback
28310					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
28311				}
28312			} else {
28313				if (!vars.isInFullScreen) vars.isInFullScreen = true;
28314				else vars.isInFullScreen = false;
28315			}
28316			iL.repositionPhoto(true);
28317		},
28318
28319		closeAction: function() {
28320			var iL = this,
28321				vars = iL.vars,
28322				opts = iL.options;
28323
28324			$win.unbind('.iLightBox');
28325			$doc.off('.iLightBox');
28326
28327			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
28328
28329			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
28330
28331			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
28332				vars.overlay.remove();
28333				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
28334			});
28335			else {
28336				vars.overlay.remove();
28337				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
28338			}
28339
28340			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
28341
28342			$.each(fadeOuts, function(i, element) {
28343				element.removeAttr('style').remove();
28344			});
28345
28346			vars.dontGenerateThumbs = vars.isInFullScreen = false;
28347
28348			window.iLightBox = null;
28349
28350			if (opts.linkId) {
28351				vars.hashLock = true;
28352				removeHash();
28353				setTimeout(function() {
28354					vars.hashLock = false;
28355				}, 55);
28356			}
28357
28358			vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
28359
28360			//Trigger the onHide callback
28361			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
28362		},
28363
28364		repositionPhoto: function() {
28365			var iL = this,
28366				vars = iL.vars,
28367				opts = iL.options,
28368				path = opts.path.toLowerCase(),
28369				viewport = getViewport(),
28370				winWidth = viewport.width,
28371				winHeight = viewport.height;
28372
28373			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
28374
28375			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
28376				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
28377				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
28378				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
28379				offsetW = (path == 'horizontal') ? parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((width / 10) <= 30) ? 30 : (width / 10))) : parseInt(((width / 10) <= 30) ? 30 : (width / 10)) + thumbsOffsetW,
28380				offsetH = (path == 'horizontal') ? parseInt(((height / 10) <= 30) ? 30 : (height / 10)) + thumbsOffsetH : parseInt((iL.items[vars.next] || iL.items[vars.prev]) ? ((opts.styles.nextOffsetX + opts.styles.prevOffsetX)) * 2 : (((height / 10) <= 30) ? 30 : (height / 10)));
28381
28382			var elObject = {
28383				type: 'current',
28384				width: width,
28385				height: height,
28386				item: iL.items[vars.current],
28387				offsetW: offsetW,
28388				offsetH: offsetH,
28389				thumbsOffsetW: thumbsOffsetW,
28390				thumbsOffsetH: thumbsOffsetH,
28391				animate: arguments.length,
28392				holder: vars.holder
28393			};
28394
28395			iL.repositionEl(elObject);
28396
28397			if (iL.items[vars.next]) {
28398				elObject = $.extend(elObject, {
28399					type: 'next',
28400					item: iL.items[vars.next],
28401					offsetX: opts.styles.nextOffsetX,
28402					offsetY: opts.styles.nextOffsetY,
28403					holder: vars.nextPhoto
28404				});
28405
28406				iL.repositionEl(elObject);
28407			}
28408
28409			if (iL.items[vars.prev]) {
28410				elObject = $.extend(elObject, {
28411					type: 'prev',
28412					item: iL.items[vars.prev],
28413					offsetX: opts.styles.nextOffsetX,
28414					offsetY: opts.styles.prevOffsetY,
28415					holder: vars.prevPhoto
28416				});
28417
28418				iL.repositionEl(elObject);
28419			}
28420
28421			var loaderCss = (path == "horizontal") ? {
28422				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
28423			} : {
28424				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
28425			};
28426			vars.loader.css(loaderCss);
28427		},
28428
28429		repositionEl: function(obj) {
28430			var iL = this,
28431				vars = iL.vars,
28432				opts = iL.options,
28433				path = opts.path.toLowerCase(),
28434				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
28435				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
28436				itemParent = obj.item,
28437				item = obj.item.options,
28438				holder = obj.holder,
28439				offsetX = obj.offsetX || 0,
28440				offsetY = obj.offsetY || 0,
28441				//Uncode change ##START##
28442				toolbarHeight = $('.ilightbox-inner-toolbar', holder).length ? parseInt( $('.ilightbox-inner-toolbar', holder).outerHeight() ) : 0,
28443				//Uncode change ##END##
28444				thumbsOffsetW = obj.thumbsOffsetW,
28445				thumbsOffsetH = obj.thumbsOffsetH;
28446
28447			if (obj.type == 'current') {
28448				if (typeof item.width == 'number' && item.width) widthAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? widthAvail : ((item.width > widthAvail) ? widthAvail : item.width);
28449				if (typeof item.height == 'number' && item.height) heightAvail = ((vars.isInFullScreen && opts.fullAlone) && (opts.fullStretchTypes.indexOf(itemParent.type) != -1 || item.fullViewPort || opts.fullViewPort)) ? heightAvail : ((item.height > heightAvail) ? heightAvail : item.height);
28450			} else {
28451				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
28452				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
28453			}
28454
28455
28456			//Uncode change ##START##
28457			heightAvail = parseInt(heightAvail - toolbarHeight);
28458			// heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
28459			//Uncode change ##END##
28460
28461			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
28462				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
28463
28464			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
28465					width: width,
28466					height: height
28467				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
28468				newDims = $.extend({}, dims, {});
28469
28470			if (obj.type == 'prev' || obj.type == 'next')
28471				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
28472				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
28473			else
28474				width = dims.width,
28475				height = dims.height;
28476
28477			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
28478				heightDiff = parseInt((getPixel(holder, 'padding-top') + getPixel(holder, 'padding-bottom') + getPixel(holder, 'border-top-width') + getPixel(holder, 'border-bottom-width') + ($('.ilightbox-inner-toolbar', holder).outerHeight() || 0)) / 2);
28479
28480			switch (obj.type) {
28481				case 'current':
28482					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
28483						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
28484					break;
28485
28486				case 'next':
28487					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
28488						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
28489					break;
28490
28491				case 'prev':
28492					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
28493						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
28494					break;
28495			}
28496
28497			holder.data('offset', {
28498				top: top,
28499				left: left,
28500				newDims: newDims,
28501				diff: {
28502					W: widthDiff,
28503					H: heightDiff
28504				},
28505				thumbsOffset: {
28506					W: thumbsOffsetW,
28507					H: thumbsOffsetH
28508				},
28509				object: obj
28510			});
28511
28512			var opacityMobile;
28513			if ( isMobile ) {
28514				opacityMobile = {
28515					opacity: 1,
28516					top: top,
28517					left: left
28518				};
28519			} else {
28520				opacityMobile = {
28521					top: top,
28522					left: left
28523				};
28524			}
28525
28526			if (obj.animate > 0 && opts.effects.reposition) {
28527				holder.css(transform, gpuAcceleration).stop().animate(
28528					opacityMobile,
28529					opts.effects.repositionSpeed, 'easeOutCirc', function() {
28530					holder.css(transform, '');
28531				});
28532				$('div.ilightbox-container', holder).stop().animate({
28533					width: width,
28534					height: height
28535				}, opts.effects.repositionSpeed, 'easeOutCirc');
28536				$('div.ilightbox-inner-toolbar', holder).stop().animate({
28537					width: width
28538				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
28539					$(this).css('overflow', 'visible');
28540				});
28541			} else {
28542				holder.css(opacityMobile);
28543				$('div.ilightbox-container', holder).css({
28544					width: width,
28545					height: height
28546				});
28547				$('div.ilightbox-inner-toolbar', holder).css({
28548					width: width
28549				});
28550			}
28551		},
28552
28553
28554		resume: function(priority) {
28555			var iL = this,
28556				vars = iL.vars,
28557				opts = iL.options;
28558
28559			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
28560				return;
28561			}
28562
28563			vars.isPaused = 0;
28564
28565			if (vars.cycleID) {
28566				vars.cycleID = clearTimeout(vars.cycleID);
28567			}
28568
28569			vars.cycleID = setTimeout(function() {
28570				if (vars.current == vars.total - 1) iL.goTo(0);
28571				else iL.moveTo('next');
28572			}, opts.slideshow.pauseTime);
28573		},
28574
28575		pause: function(priority) {
28576			var iL = this,
28577				vars = iL.vars,
28578				opts = iL.options;
28579
28580			if (priority < vars.isPaused) {
28581				return;
28582			}
28583
28584			vars.isPaused = priority || 100;
28585
28586			if (vars.cycleID) {
28587				vars.cycleID = clearTimeout(vars.cycleID);
28588			}
28589		},
28590
28591		resetCycle: function() {
28592			var iL = this,
28593				vars = iL.vars,
28594				opts = iL.options;
28595
28596			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
28597				iL.resume();
28598			}
28599		},
28600
28601		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
28602			var iL = this;
28603
28604			if (!width) factor = height / height_old;
28605			else if (!height) factor = width / width_old;
28606			else factor = min(width / width_old, height / height_old);
28607
28608			if (!thumb) {
28609				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
28610				else if (factor < iL.options.minScale) factor = iL.options.minScale;
28611			}
28612
28613			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
28614				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
28615
28616			return {
28617				width: final_width,
28618				height: final_height,
28619				ratio: factor
28620			};
28621		},
28622
28623		setOption: function(options) {
28624			var iL = this;
28625
28626			iL.options = $.extend(true, iL.options, options || {});
28627			iL.refresh();
28628		},
28629
28630		availPlugins: function() {
28631			var iL = this,
28632				testEl = document.createElement("video");
28633
28634			iL.plugins = {
28635				flash: !isMobile,
28636				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
28637				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
28638				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
28639				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
28640				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
28641			};
28642		},
28643
28644		addContent: function(element, obj) {
28645			var iL = this,
28646				el;
28647
28648			switch (obj.type) {
28649				case 'video':
28650					var HTML5 = false,
28651						videoType = obj.videoType,
28652						html5video = obj.options.html5video;
28653
28654					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
28655						obj.ext = 'mp4',
28656						obj.URL = html5video.h264 || obj.URL;
28657					else if (html5video.webm && iL.plugins.html5WebM)
28658						obj.ext = 'webm',
28659						obj.URL = html5video.webm || obj.URL;
28660					else if (html5video.ogg && iL.plugins.html5Vorbis)
28661						obj.ext = 'ogv',
28662						obj.URL = html5video.ogg || obj.URL;
28663
28664					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
28665					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
28666					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
28667					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
28668
28669					if (HTML5) {
28670						el = $('<video />
28670', {
28671							"width": "100%",
28672							"height": "100%",
28673							"preload": html5video.preload,
28674							"autoplay": html5video.autoplay,
28675							"loop": html5video.loop,
28676							"poster": html5video.poster,
28677							"controls": html5video.controls,
28678							"controlslist": "nodownload"
28679						}).append($('<source />', {
28680							"src": obj.URL,
28681							"type": videoType
28682						}));
28683					} else {
28684						if (!iL.plugins.quicktime) el = $('<span />', {
28685							"class": "ilightbox-alert",
28686							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
28687						});
28688						else {
28689
28690							el = $('<object />', {
28691								"type": "video/quicktime",
28692								"pluginspage": pluginspages.quicktime
28693							}).attr({
28694								"data": obj.URL,
28695								"width": "100%",
28696								"height": "100%"
28697							}).append($('<param />', {
28698								"name": "src",
28699								"value": obj.URL
28700							})).append($('<param />', {
28701								"name": "autoplay",
28702								"value": "false"
28703							})).append($('<param />', {
28704								"name": "loop",
28705								"value": "false"
28706							})).append($('<param />', {
28707								"name": "scale",
28708								"value": "tofit"
28709							}));
28710
28711							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
28712						}
28713					}
28714
28715					break;
28716
28717				case 'flash':
28718					if (!iL.plugins.flash) el = $('<span />', {
28719						"class": "ilightbox-alert",
28720						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
28721					});
28722					else {
28723						var flashvars = "",
28724							i = 0;
28725
28726						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
28727							if (i != 0) flashvars += "&";
28728							flashvars += k + "=" + encodeURIComponent(v);
28729							i++;
28730						});
28731						else flashvars = null;
28732
28733						el = $('<embed />').attr({
28734							"type": "application/x-shockwave-flash",
28735							"src": obj.URL,
28736							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
28737							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
28738							"quality": "high",
28739							"bgcolor": "#000000",
28740							"play": "true",
28741							"loop": "true",
28742							"menu": "true",
28743							"wmode": "transparent",
28744							"scale": "showall",
28745							"allowScriptAccess": "always",
28746							"allowFullScreen": "true",
28747							"flashvars": flashvars,
28748							"fullscreen": "yes"
28749						});
28750					}
28751
28752					break;
28753
28754				case 'iframe':
28755					el = $('<iframe />').attr({
28756						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
28757						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
28758						src: obj.URL,
28759						frameborder: 0,
28760						'hspace': 0,
28761						'vspace': 0,
28762						'scrolling': supportTouch ? 'auto' : 'scroll',
28763						'webkitAllowFullScreen': '',
28764						'mozallowfullscreen': '',
28765						'allowFullScreen': ''
28766					});
28767
28768					break;
28769
28770				case 'inline':
28771					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
28772
28773					break;
28774
28775				case 'html':
28776					var object = obj.URL,
28777						el;
28778
28779					if (object[0].nodeName) {
28780						el = $('<div class="ilightbox-wrapper"></div>').html(object);
28781					} else {
28782						var dom = $(obj.URL),
28783							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
28784						el = $('<div class="ilightbox-wrapper"></div>').html(html);
28785					}
28786
28787					break;
28788			}
28789
28790			$('div.ilightbox-container', element).empty().html(el);
28791
28792			// For fixing Chrome about just playing the video for first time
28793			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
28794				var src = el[0].currentSrc + '?' + floor(random() * 30000);
28795				el[0].currentSrc = src;
28796				el[0].src = src;
28797			});
28798
28799			return el;
28800		},
28801
28802		ogpRecognition: function(obj, callback) {
28803			var iL = this,
28804				url = obj.URL;
28805
28806			iL.showLoader();
28807			doAjax(url, function(data) {
28808				iL.hideLoader();
28809				if (data) {
28810					var object = new Object();
28811
28812					object.length = false,
28813					object.url = data.url;
28814
28815					if (data.status == 200) {
28816						var result = data.results,
28817							type = result.type,
28818							source = result.source;
28819
28820						object.source = source.src,
28821						object.width = source.width && parseInt(source.width) || 0,
28822						object.height = source.height && parseInt(source.height) || 0,
28823						object.type = type,
28824						object.thumbnail = source.thumbnail || result.images && result.images[0],
28825						object.html5video = result.html5video || {},
28826						object.length = true;
28827
28828						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
28829						else if (source.type.indexOf("video/") != -1) object.type = "video";
28830						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
28831						else if (source.type.indexOf("image/") != -1) object.type = "image";
28832
28833					} else if (typeof data.response != 'undefined')
28834						throw data.response;
28835
28836					callback.call(this, object.length ? object : false);
28837				}
28838			});
28839		},
28840
28841		hashChangeHandler: function(url) {
28842			var iL = this,
28843				vars = iL.vars,
28844				opts = iL.options,
28845				URL = url || window.location.href,
28846				hash = parseURI(URL).hash,
28847				split = hash.split('/'),
28848				index = split[1];
28849
28850			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
28851
28852			if (index) {
28853				var target = split[1] || 0;
28854				if (iL.items[target]) {
28855					var overlay = $('.ilightbox-overlay');
28856					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
28857						iL.goTo(target);
28858					} else {
28859						iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click');
28860						//iL.goTo(target);
28861					}
28862				} else {
28863					var overlay = $('.ilightbox-overlay');
28864					if (overlay.length) iL.closeAction();
28865				}
28866			} else {
28867				var overlay = $('.ilightbox-overlay');
28868				if (overlay.length) iL.closeAction();
28869			}
28870		}
28871	};
28872
28873	/**
28874	 * Parse style to pixels.
28875	 *
28876	 * @param {Object}   $element   jQuery object with element.
28877	 * @param {Property} property   CSS property to get the pixels from.
28878	 *
28879	 * @return {Int}
28880	 */
28881	function getPixel($element, property) {
28882		return parseInt($element.css(property), 10) || 0;
28883	}
28884
28885	/**
28886	 * Make sure that number is within the limits.
28887	 *
28888	 * @param {Number} number
28889	 * @param {Number} min
28890	 * @param {Number} max
28891	 *
28892	 * @return {Number}
28893	 */
28894	function within(number, min, max) {
28895		return number < min ? min : number > max ? max : number;
28896	}
28897
28898	/**
28899	 * Get viewport/window size (width and height).
28900	 *
28901	 * @return {Object}
28902	 */
28903	function getViewport() {
28904		var e = window,
28905			a = 'inner';
28906		if (!('innerWidth' in window)) {
28907			a = 'client';
28908			e = document.documentElement || document.body;
28909		}
28910		return {
28911			width: e[a + 'Width'],
28912			height: e[a + 'Height']
28913		}
28914	}
28915
28916	/**
28917	 * Remove hash tag from the URL
28918	 *
28919	 * @return {Void}
28920	 */
28921	function removeHash() {
28922		var scroll = getScrollXY();
28923
28924		//UNCODE change
28925		// window.location.hash = "";
28926		// history.pushState("", document.title, window.location.pathname + window.location.search);
28927		history.replaceState({}, document.title, window.location.pathname + window.location.search);
28928
28929		// Restore the scroll offset, should be flicker free
28930		window.scrollTo(scroll.x, scroll.y);
28931	}
28932
28933	/**
28934	 * Do the ajax requests with callback.
28935	 *
28936	 * @param {String}   url
28937	 * @param {Function} callback
28938	 *
28939	 * @return {Void}
28940	 */
28941	function doAjax(url, callback) {
28942		var url = "//ilightbox.net/getSource/jsonp.php?url=" + encodeURIComponent(url).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A');
28943		$.ajax({
28944			url: url,
28945			dataType: 'jsonp'
28946		});
28947
28948		iLCallback = function(data) {
28949			callback.call(this, data);
28950		};
28951	}
28952
28953	/**
28954	 * Find image from DOM elements
28955	 *
28956	 * @param {Element} element
28957	 *
28958	 * @return {Void}
28959	 */
28960	function findImageInElement(element) {
28961		var elements = $('*', element),
28962			imagesArr = new Array();
28963
28964		elements.each(function() {
28965			var url = "",
28966				element = this;
28967
28968			if ($(element).css("background-image") != "none") {
28969				url = $(element).css("background-image");
28970			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
28971				url = $(element).attr("src");
28972			}
28973
28974			if (url.indexOf("gradient") == -1) {
28975				url = url.replace(/url\(\"/g, "");
28976				url = url.replace(/url\(/g, "");
28977				url = url.replace(/\"\)/g, "");
28978				url = url.replace(/\)/g, "");
28979
28980				var urls = url.split(",");
28981
28982				for (var i = 0; i < urls.length; i++) {
28983					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
28984						var extra = "";
28985						if (browser.msie && browser.version < 9) {
28986							extra = "?" + floor(random() * 3000);
28987						}
28988						imagesArr.push(urls[i] + extra);
28989					}
28990				}
28991			}
28992		});
28993
28994		return imagesArr;
28995	}
28996
28997	/**
28998	 * Get file extension.
28999	 *
29000	 * @param {String} URL
29001	 *
29002	 * @return {String}
29003	 */
29004	function getExtension(URL) {
29005		if (URL !== null) {
29006			//UNCODE: fix issue to detect media type with query strings
29007			var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL;
29008			ext = ext.split('.').pop().toLowerCase();
29009
29010			return ext;
29011		}
29012	}
29013
29014	/**
29015	 * Get type via extension.
29016	 *
29017	 * @param {String} URL
29018	 *
29019	 * @return {String}
29020	 */
29021	function getTypeByExtension(URL) {
29022		var type,
29023			ext = getExtension(URL);
29024
29025		//Uncode addition ##START##
29026		if (URL == undefined) {
29027			return false;
29028		}
29029		//Uncode addition ##END##
29030
29031		if (extensions.image.indexOf(ext) !== -1) type = 'image';
29032		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
29033		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
29034		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
29035		else type = 'iframe';
29036
29037		return type;
29038	}
29039
29040	/**
29041	 * Return value from percent of a number.
29042	 *
29043	 * @param {Number} percent
29044	 * @param {Number} total
29045	 *
29046	 * @return {Number}
29047	 */
29048	function percentToValue(percent, total) {
29049		return parseInt((total / 100) * percent);
29050	}
29051
29052	/**
29053	 * A JavaScript equivalent of PHP’s parse_url.
29054	 *
29055	 * @param {String} url           The URL to parse.
29056	 *
29057	 * @return {Mixed}
29058	 */
29059	function parseURI(url) {
29060		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
29061		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
29062		return (m ? {
29063			href: m[0] || '',
29064			protocol: m[1] || '',
29065			authority: m[2] || '',
29066			host: m[3] || '',
29067			hostname: m[4] || '',
29068			port: m[5] || '',
29069			pathname: m[6] || '',
29070			search: m[7] || '',
29071			hash: m[8] || ''
29072		} : null);
29073	}
29074
29075	/**
29076	 * Gets the absolute URI.
29077	 *
29078	 * @param {String} href     The relative URL.
29079	 * @param {String} base     The base URL.
29080	 *
29081	 * @return {String}         The absolute URL.
29082	 */
29083	function absolutizeURI(base, href) { // RFC 3986
29084		var iL = this;
29085
29086		function removeDotSegments(input) {
29087			var output = [];
29088			input.replace(/^(\.\.?(\/|$))+/, '')
29089				.replace(/\/(\.(\/|$))+/g, '/')
29090				.replace(/\/\.\.$/, '/../')
29091				.replace(/\/?[^\/]*/g, function(p) {
29092					if (p === '/..') {
29093						output.pop();
29094					} else {
29095						output.push(p);
29096					}
29097				});
29098			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
29099		}
29100
29101		href = parseURI(href || '');
29102		base = parseURI(base || '');
29103
29104		return !href || !base ? null : (href.protocol || base.protocol) +
29105			(href.protocol || href.authority ? href.authority : base.authority) +
29106			removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
29107			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
29108			href.hash;
29109	}
29110
29111	/**
29112	 * A JavaScript equivalent of PHP’s version_compare.
29113	 *
29114	 * @param {String} v1
29115	 * @param {String} v2
29116	 * @param {String} operator
29117	 *
29118	 * @return {Boolean}
29119	 */
29120	function version_compare(v1, v2, operator) {
29121		this.php_js = this.php_js || {};
29122		this.php_js.ENV = this.php_js.ENV || {};
29123		var i = 0,
29124			x = 0,
29125			compare = 0,
29126			vm = {
29127				'dev': -6,
29128				'alpha': -5,
29129				'a': -5,
29130				'beta': -4,
29131				'b': -4,
29132				'RC': -3,
29133				'rc': -3,
29134				'#': -2,
29135				'p': 1,
29136				'pl': 1
29137			},
29138			prepVersion = function(v) {
29139				v = ('' + v).replace(/[_\-+]/g, '.');
29140				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
29141				return (!v.length ? [-8] : v.split('.'));
29142			},
29143			numVersion = function(v) {
29144				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
29145			};
29146		v1 = prepVersion(v1);
29147		v2 = prepVersion(v2);
29148		x = max(v1.length, v2.length);
29149		for (i = 0; i < x; i++) {
29150			if (v1[i] == v2[i]) {
29151				continue;
29152			}
29153			v1[i] = numVersion(v1[i]);
29154			v2[i] = numVersion(v2[i]);
29155			if (v1[i] < v2[i]) {
29156				compare = -1;
29157				break;
29158			} else if (v1[i] > v2[i]) {
29159				compare = 1;
29160				break;
29161			}
29162		}
29163		if (!operator) {
29164			return compare;
29165		}
29166
29167		switch (operator) {
29168			case '>':
29169			case 'gt':
29170				return (compare > 0);
29171			case '>=':
29172			case 'ge':
29173				return (compare >= 0);
29174			case '<=':
29175			case 'le':
29176				return (compare <= 0);
29177			case '==':
29178			case '=':
29179			case 'eq':
29180				return (compare === 0);
29181			case '<>':
29182			case '!=':
29183			case 'ne':
29184				return (compare !== 0);
29185			case '':
29186			case '<':
29187			case 'lt':
29188				return (compare < 0);
29189			default:
29190				return null;
29191		}
29192	}
29193
29194
29195	// Begin the iLightBox plugin
29196	$.fn.iLightBox = function() {
29197
29198		var args = arguments,
29199			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
29200			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
29201
29202		if (!opt) opt = {};
29203
29204		// Default options. Play carefully.
29205		var options = $.extend(true, {
29206			attr: 'href',
29207			path: 'vertical',
29208			skin: 'dark',
29209			linkId: false,
29210			infinite: false,
29211			startFrom: 0,
29212			randomStart: false,
29213			keepAspectRatio: true,
29214			maxScale: 1,
29215			minScale: .2,
29216			innerToolbar: false,
29217			smartRecognition: false,
29218			mobileOptimizer: true,
29219			fullAlone: true,
29220			fullViewPort: null,
29221			fullStretchTypes: 'flash, video',
29222			overlay: {
29223				blur: true,
29224				opacity: .85
29225			},
29226			controls: {
29227				arrows: false,
29228				slideshow: false,
29229				toolbar: true,
29230				fullscreen: true,
29231				thumbnail: true,
29232				keyboard: true,
29233				mousewheel: true,
29234				swipe: true
29235			},
29236			keyboard: {
29237				left: true, // previous
29238				right: true, // next
29239				up: true, // previous
29240				down: true, // next
29241				esc: true, // close
29242				shift_enter: true // fullscreen
29243			},
29244			show: {
29245				effect: true,
29246				speed: 300,
29247				title: true
29248			},
29249			hide: {
29250				effect: true,
29251				speed: 300
29252			},
29253			caption: {
29254				start: true,
29255				show: 'mouseenter',
29256				hide: 'mouseleave'
29257			},
29258			social: {
29259				start: true,
29260				show: 'mouseenter',
29261				hide: 'mouseleave',
29262				buttons: false
29263			},
29264			styles: {
29265				pageOffsetX: 0,
29266				pageOffsetY: 0,
29267				nextOffsetX: 45,
29268				nextOffsetY: 0,
29269				nextOpacity: 1,
29270				nextScale: 1,
29271				prevOffsetX: 45,
29272				prevOffsetY: 0,
29273				prevOpacity: 1,
29274				prevScale: 1
29275			},
29276			thumbnails: {
29277				maxWidth: 120,
29278				maxHeight: 80,
29279				normalOpacity: 1,
29280				activeOpacity: .6
29281			},
29282			effects: {
29283				reposition: true,
29284				repositionSpeed: 200,
29285				switchSpeed: 500,
29286				loadedFadeSpeed: 180,
29287				fadeSpeed: 200
29288			},
29289			slideshow: {
29290				pauseTime: 5000,
29291				pauseOnHover: false,
29292				startPaused: true
29293			},
29294			text: {
29295				close: "Press Esc to close",
29296				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
29297				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
29298				slideShow: "Slideshow",
29299				next: "Next",
29300				previous: "Previous"
29301			},
29302			errors: {
29303				loadImage: "An error occurred when trying to load photo.",
29304				loadContents: "An error occurred when trying to load contents.",
29305				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
29306			},
29307			ajaxSetup: {
29308				url: '',
29309				beforeSend: function(jqXHR, settings) {},
29310				cache: false,
29311				complete: function(jqXHR, textStatus) {},
29312				crossDomain: false,
29313				error: function(jqXHR, textStatus, errorThrown) {},
29314				success: function(data, textStatus, jqXHR) {},
29315				global: true,
29316				ifModified: false,
29317				username: null,
29318				password: null,
29319				type: 'GET'
29320			},
29321			callback: {}
29322		}, opt);
29323
29324		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
29325
29326		items = $.isArray(items) ? items : new Array();
29327
29328		if (typeof args[0] == 'string') items[0] = args[0];
29329
29330		if (version_compare($.fn.jquery, '1.8', '>=')) {
29331			var iLB = new iLightBox($(this), options, items, instant);
29332			return {
29333				close: function() {
29334					iLB.closeAction();
29335				},
29336				fullscreen: function() {
29337					iLB.fullScreenAction();
29338				},
29339				moveNext: function() {
29340					iLB.moveTo('next');
29341				},
29342				movePrev: function() {
29343					iLB.moveTo('prev');
29344				},
29345				goTo: function(index) {
29346					iLB.goTo(index);
29347				},
29348				refresh: function() {
29349					iLB.refresh();
29350				},
29351				reposition: function() {
29352					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
29353				},
29354				setOption: function(options) {
29355					iLB.setOption(options);
29356				},
29357				destroy: function() {
29358					iLB.closeAction();
29359					iLB.dispatchItemsEvents();
29360				}
29361			};
29362		} else {
29363			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
29364		}
29365
29366	};
29367
29368
29369	$.iLightBox = function() {
29370		return $.fn.iLightBox(arguments[0], arguments[1]);
29371	};
29372
29373	function getScrollXY() {
29374		var scrOfX = 0,
29375			scrOfY = 0;
29376		if (typeof(window.pageYOffset) == 'number') {
29377			//Netscape compliant
29378			scrOfY = window.pageYOffset;
29379			scrOfX = window.pageXOffset;
29380		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
29381			//DOM compliant
29382			scrOfY = document.body.scrollTop;
29383			scrOfX = document.body.scrollLeft;
29384		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
29385			//IE6 standards compliant mode
29386			scrOfY = document.documentElement.scrollTop;
29387			scrOfX = document.documentElement.scrollLeft;
29388		}
29389		return {
29390			x: scrOfX,
29391			y: scrOfY
29392		};
29393	}
29394
29395	(function() {
29396		// add new event shortcuts
29397		$.each(("touchstart touchmove touchend " +
29398			"tap taphold " +
29399			"swipe swipeleft swiperight " +
29400			"scrollstart scrollstop").split(" "), function(i, name) {
29401
29402			$.fn[name] = function(fn) {
29403				return fn ? this.bind(name, fn) : this.trigger(name);
29404			};
29405
29406			// jQuery < 1.8
29407			// if ($.attrFn) {
29408			// 	$.attrFn[name] = true;
29409			// }
29410		});
29411
29412		var tapSettings = {
29413			startEvent: 'touchstart.iTap',
29414			endEvent: 'touchend.iTap'
29415		};
29416
29417		// tap Event:
29418		$.event.special.itap = {
29419			setup: function() {
29420
29421				var self = this,
29422					$self = $(this),
29423					start, stop;
29424
29425				$self.bind(tapSettings.startEvent, function(event) {
29426					start = getScrollXY();
29427
29428					$self.one(tapSettings.endEvent, function(event) {
29429						stop = getScrollXY();
29430
29431						var orgEvent = event || window.event;
29432						event = $.event.fix(orgEvent);
29433						event.type = "itap";
29434
29435						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
29436
29437						start = stop = undefined;
29438					});
29439				});
29440			},
29441
29442			teardown: function() {
29443				$(this).unbind(tapSettings.startEvent);
29444			}
29445		};
29446	}());
29447
29448
29449	//Fullscreen API
29450	(function() {
29451		fullScreenApi = {
29452				supportsFullScreen: false,
29453				isFullScreen: function() {
29454					return false;
29455				},
29456				requestFullScreen: function() {},
29457				cancelFullScreen: function() {},
29458				fullScreenEventName: '',
29459				prefix: ''
29460			},
29461			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
29462
29463		// check for native support
29464		if (typeof document.cancelFullScreen != 'undefined') {
29465			fullScreenApi.supportsFullScreen = true;
29466		} else {
29467			// check for fullscreen support by vendor prefix
29468			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
29469				fullScreenApi.prefix = browserPrefixes[i];
29470
29471				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
29472					fullScreenApi.supportsFullScreen = true;
29473
29474					break;
29475				}
29476			}
29477		}
29478
29479		// update methods to do something useful
29480		if (fullScreenApi.supportsFullScreen) {
29481			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
29482
29483			fullScreenApi.isFullScreen = function() {
29484				switch (this.prefix) {
29485					case '':
29486						return document.fullScreen;
29487					case 'webkit':
29488						return document.webkitIsFullScreen;
29489					default:
29490						return document[this.prefix + 'FullScreen'];
29491				}
29492			}
29493			fullScreenApi.requestFullScreen = function(el) {
29494				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
29495			}
29496			fullScreenApi.cancelFullScreen = function(el) {
29497				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
29498			}
29499		}
29500	}());
29501
29502	// Browser detect
29503	(function() {
29504		function uaMatch(ua) {
29505			ua = ua.toLowerCase();
29506
29507			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
29508				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
29509				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
29510				/(msie) ([\w.]+)/.exec(ua) ||
29511				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
29512
29513			return {
29514				browser: match[1] || "",
29515				version: match[2] || "0"
29516			};
29517		}
29518
29519		var matched = uaMatch(navigator.userAgent);
29520		browser = {};
29521
29522		if (matched.browser) {
29523			browser[matched.browser] = true;
29524			browser.version = matched.version;
29525		}
29526
29527		// Chrome is Webkit, but Webkit is also Safari.
29528		if (browser.chrome) {
29529			browser.webkit = true;
29530		} else if (browser.webkit) {
29531			browser.safari = true;
29532		}
29533	}());
29534
29535	// Feature detects
29536	(function() {
29537		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
29538		var el = document.createElement('div');
29539
29540		function testProp(prop) {
29541			for (var p = 0, pl = prefixes.length; p < pl; p++) {
29542				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
29543				if (el.style[prefixedProp] !== undefined) {
29544					return prefixedProp;
29545				}
29546			}
29547		}
29548
29549		// Global support indicators
29550		transform = testProp('transform') || '';
29551		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
29552	}());
29553
29554
29555	/*
29556		PluginDetect v0.7.9
29557		www.pinlady.net/PluginDetect/license/
29558		[ getVersion onWindowLoaded BetterIE ]
29559		[ Flash QuickTime Shockwave ]
29560	*/
29561	var PluginDetect={version:"0.7.9",name:"PluginDetect",handler:function(c,b,a){return function(){c(b,a)}},openTag:"<",isDefined:function(b){return typeof b!="undefined"},isArray:function(b){return(/array/i).test(Object.prototype.toString.call(b))},isFunc:function(b){return typeof b=="function"},isString:function(b){return typeof b=="string"},isNum:function(b){return typeof b=="number"},isStrNum:function(b){return(typeof b=="string"&&(/\d/).test(b))},getNumRegx:/[\d][\d\.\_,-]*/,splitNumRegx:/[\.\_,-]/g,getNum:function(b,c){var d=this,a=d.isStrNum(b)?(d.isDefined(c)?new RegExp(c):d.getNumRegx).exec(b):null;return a?a[0]:null},compareNums:function(h,f,d){var e=this,c,b,a,g=parseInt;if(e.isStrNum(h)&&e.isStrNum(f)){if(e.isDefined(d)&&d.compareNums){return d.compareNums(h,f)}c=h.split(e.splitNumRegx);b=f.split(e.splitNumRegx);for(a=0;a<min(c.length,b.length);a++){if(g(c[a],10)>g(b[a],10)){return 1}if(g(c[a],10)<g(b[a],10)){return -1}}}return 0},formatNum:function(b,c){var d=this,a,e;if(!d.isStrNum(b)){return null}if(!d.isNum(c)){c=4}c--;e=b.replace(/\s/g,"").split(d.splitNumRegx).concat(["0","0","0","0"]);for(a=0;a<4;a++){if(/^(0+)(.+)$/.test(e[a])){e[a]=RegExp.$2}if(a>c||!(/\d/).test(e[a])){e[a]="0"}}return e.slice(0,4).join(",")},$$hasMimeType:function(a){return function(c){if(!a.isIE&&c){var f,e,b,d=a.isArray(c)?c:(a.isString(c)?[c]:[]);for(b=0;b<d.length;b++){if(a.isString(d[b])&&/[^\s]/.test(d[b])){f=navigator.mimeTypes[d[b]];e=f?f.enabledPlugin:0;if(e&&(e.name||e.description)){return f}}}}return null}},findNavPlugin:function(l,e,c){var j=this,h=new RegExp(l,"i"),d=(!j.isDefined(e)||e)?/\d/:0,k=c?new RegExp(c,"i"):0,a=navigator.plugins,g="",f,b,m;for(f=0;f<a.length;f++){m=a[f].description||g;b=a[f].name||g;if((h.test(m)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))||(h.test(b)&&(!d||d.test(RegExp.leftContext+RegExp.rightContext)))){if(!k||!(k.test(m)||k.test(b))){return a[f]}}}return null},getMimeEnabledPlugin:function(k,m,c){var e=this,f,b=new RegExp(m,"i"),h="",g=c?new RegExp(c,"i"):0,a,l,d,j=e.isString(k)?[k]:k;for(d=0;d<j.length;
29561d++){if((f=e.hasMimeType(j[d]))&&(f=f.enabledPlugin)){l=f.description||h;a=f.name||h;if(b.test(l)||b.test(a)){if(!g||!(g.test(l)||g.test(a))){return f}}}}return 0},getPluginFileVersion:function(f,b){var h=this,e,d,g,a,c=-1;if(h.OS>2||!f||!f.version||!(e=h.getNum(f.version))){return b}if(!b){return e}e=h.formatNum(e);b=h.formatNum(b);d=b.split(h.splitNumRegx);g=e.split(h.splitNumRegx);for(a=0;a<d.length;a++){if(c>-1&&a>c&&d[a]!="0"){return b}if(g[a]!=d[a]){if(c==-1){c=a}if(d[a]!="0"){return b}}}return e},AXO:window.ActiveXObject,getAXO:function(a){var f=null,d,b=this,c={};try{f=new b.AXO(a)}catch(d){}return f},convertFuncs:function(f){var a,g,d,b=/^[\$][\$]/,c=this;for(a in f){if(b.test(a)){try{g=a.slice(2);if(g.length>0&&!f[g]){f[g]=f[a](f);delete f[a]}}catch(d){}}}},initObj:function(e,b,d){var a,c;if(e){if(e[b[0]]==1||d){for(a=0;a<b.length;a=a+2){e[b[a]]=b[a+1]}}for(a in e){c=e[a];if(c&&c[b[0]]==1){this.initObj(c,b)}}}},initScript:function(){var d=this,a=navigator,h,i=document,l=a.userAgent||"",j=a.vendor||"",b=a.platform||"",k=a.product||"";d.initObj(d,["$",d]);for(h in d.Plugins){if(d.Plugins[h]){d.initObj(d.Plugins[h],["$",d,"$$",d.Plugins[h]],1)}}d.convertFuncs(d);d.OS=100;if(b){var g=["Win",1,"Mac",2,"Linux",3,"FreeBSD",4,"iPhone",21.1,"iPod",21.2,"iPad",21.3,"Win.*CE",22.1,"Win.*Mobile",22.2,"Pocket\\s*PC",22.3,"",100];for(h=g.length-2;h>=0;h=h-2){if(g[h]&&new RegExp(g[h],"i").test(b)){d.OS=g[h+1];break}}};d.head=i.getElementsByTagName("head")[0]||i.getElementsByTagName("body")[0]||i.body||null;d.isIE=new Function("return/*@cc_on!@*/!1")();d.verIE=d.isIE&&(/MSIE\s*(\d+\.?\d*)/i).test(l)?parseFloat(RegExp.$1,10):null;d.verIEfull=null;d.docModeIE=null;if(d.isIE){var f,n,c=document.createElement("div");try{c.style.behavior="url(#default#clientcaps)";d.verIEfull=(c.getComponentVersion("{89820200-ECBD-11CF-8B85-00AA005B4383}","componentid")).replace(/,/g,".")}catch(f){}n=parseFloat(d.verIEfull||"0",10);d.docModeIE=i.documentMode||((/back/i).test(i.compatMode||"")?5:n)||d.verIE;d.verIE=n||d.docModeIE};d.ActiveXEnabled=false;if(d.isIE){var h,m=["Msxml2.XMLHTTP","Msxml2.DOMDocument","Microsoft.XMLDOM","ShockwaveFlash.ShockwaveFlash","TDCCtl.TDCCtl","Shell.UIHelper","Scripting.Dictionary","wmplayer.ocx"];for(h=0;h<m.length;h++){if(d.getAXO(m[h])){d.ActiveXEnabled=true;break}}};d.isGecko=(/Gecko/i).test(k)&&(/Gecko\s*\/\s*\d/i).test(l);
29561d.verGecko=d.isGecko?d.formatNum((/rv\s*\:\s*([\.\,\d]+)/i).test(l)?RegExp.$1:"0.9"):null;d.isChrome=(/Chrome\s*\/\s*(\d[\d\.]*)/i).test(l);d.verChrome=d.isChrome?d.formatNum(RegExp.$1):null;d.isSafari=((/Apple/i).test(j)||(!j&&!d.isChrome))&&(/Safari\s*\/\s*(\d[\d\.]*)/i).test(l);d.verSafari=d.isSafari&&(/Version\s*\/\s*(\d[\d\.]*)/i).test(l)?d.formatNum(RegExp.$1):null;d.isOpera=(/Opera\s*[\/]?\s*(\d+\.?\d*)/i).test(l);d.verOpera=d.isOpera&&((/Version\s*\/\s*(\d+\.?\d*)/i).test(l)||1)?parseFloat(RegExp.$1,10):null;d.addWinEvent("load",d.handler(d.runWLfuncs,d))},init:function(d){var c=this,b,d,a={status:-3,plugin:0};if(!c.isString(d)){return a}if(d.length==1){c.getVersionDelimiter=d;return a}d=d.toLowerCase().replace(/\s/g,"");b=c.Plugins[d];if(!b||!b.getVersion){return a}a.plugin=b;if(!c.isDefined(b.installed)){b.installed=null;b.version=null;b.version0=null;b.getVersionDone=null;b.pluginName=d}c.garbage=false;if(c.isIE&&!c.ActiveXEnabled&&d!=="java"){a.status=-2;return a}a.status=1;return a},fPush:function(b,a){var c=this;if(c.isArray(a)&&(c.isFunc(b)||(c.isArray(b)&&b.length>0&&c.isFunc(b[0])))){a.push(b)}},callArray:function(b){var c=this,a;if(c.isArray(b)){for(a=0;a<b.length;a++){if(b[a]===null){return}c.call(b[a]);b[a]=null}}},call:function(c){var b=this,a=b.isArray(c)?c.length:-1;if(a>0&&b.isFunc(c[0])){c[0](b,a>1?c[1]:0,a>2?c[2]:0,a>3?c[3]:0)}else{if(b.isFunc(c)){c(b)}}},getVersionDelimiter:",",$$getVersion:function(a){return function(g,d,c){var e=a.init(g),f,b,h={};if(e.status<0){return null};f=e.plugin;if(f.getVersionDone!=1){f.getVersion(null,d,c);if(f.getVersionDone===null){f.getVersionDone=1}}a.cleanup();b=(f.version||f.version0);b=b?b.replace(a.splitNumRegx,a.getVersionDelimiter):b;return b}},cleanup:function(){var a=this;if(a.garbage&&a.isDefined(window.CollectGarbage)){window.CollectGarbage()}},isActiveXObject:function(d,b){var f=this,a=false,g,c='<object width="1" height="1" style="display:none" '+d.getCodeBaseVersion(b)+">"+d.HTML+f.openTag+"/object>";if(!f.head){return a}f.head.insertBefore(document.createElement("object"),f.head.firstChild);f.head.firstChild.outerHTML=c;try{f.head.firstChild.classid=d.classID}catch(g){}try{if(f.head.firstChild.object){a=true}}catch(g){}try{if(a&&f.head.firstChild.readyState<4){f.garbage=true}}catch(g){}f.head.removeChild(f.head.firstChild);return a},codebaseSearch:function(f,b){var c=this;if(!c.ActiveXEnabled||!f){return null}if(f.BIfuncs&&f.BIfuncs.length&&f.BIfuncs[f.BIfuncs.length-1]!==null){c.callArray(f.BIfuncs)}var d,o=f.SEARCH,k={};if(c.isStrNum(b)){if(o.match&&o.min&&c.compareNums(b,o.min)<=0){return true}if(o.match&&o.max&&c.compareNums(b,o.max)>=0){return false}d=c.isActiveXObject(f,b);if(d&&(!o.min||c.compareNums(b,o.min)>0)){o.min=b}if(!d&&(!o.max||c.compareNums(b,o.max)<0)){o.max=b}return d};var e=[0,0,0,0],l=[].concat(o.digits),a=o.min?1:0,j,i,h,g,m,n=function(p,r){var q=[].concat(e);q[p]=r;return c.isActiveXObject(f,q.join(","))};if(o.max){g=o.max.split(c.splitNumRegx);for(j=0;j<g.length;j++){g[j]=parseInt(g[j],10)}if(g[0]<l[0]){l[0]=g[0]}}if(o.min){m=o.min.split(c.splitNumRegx);for(j=0;j<m.length;j++){m[j]=parseInt(m[j],10)}if(m[0]>e[0]){e[0]=m[0]}}if(m&&g){for(j=1;j<m.length;j++){if(m[j-1]!=g[j-1]){break}if(g[j]<l[j]){l[j]=g[j]}if(m[j]>e[j]){e[j]=m[j]}}}if(o.max){for(j=1;j<l.length;j++){if(g[j]>0&&l[j]==0&&l[j-1]<o.digits[j-1]){l[j-1]+=1;break}}};for(j=0;j<l.length;j++){h={};for(i=0;i<20;i++){if(l[j]-e[j]<1){break}d=round((l[j]+e[j])/2);if(h["a"+d]){break}h["a"+d]=1;if(n(j,d)){e[j]=d;a=1}else{l[j]=d}}l[j]=e[j];if(!a&&n(j,e[j])){a=1};if(!a){break}};return a?e.join(","):null},addWinEvent:function(d,c){var e=this,a=window,b;if(e.isFunc(c)){if(a.addEventListener){a.addEventListener(d,c,false)}else{if(a.attachEvent){a.attachEvent("on"+d,c)}else{b=a["on"+d];a["on"+d]=e.winHandler(c,b)}}}},winHandler:function(d,c){return function(){d();if(typeof c=="function"){c()}}},WLfuncs0:[],WLfuncs:[],runWLfuncs:function(a){var b={};a.winLoaded=true;a.callArray(a.WLfuncs0);a.callArray(a.WLfuncs);if(a.onDoneEmptyDiv){a.onDoneEmptyDiv()}},winLoaded:false,$$onWindowLoaded:function(a){return function(b){if(a.winLoaded){a.call(b)}else{a.fPush(b,a.WLfuncs)}}},div:null,divID:"plugindetect",divWidth:50,pluginSize:1,emptyDiv:function(){var d=this,b,h,c,a,f,g;if(d.div&&d.div.childNodes){for(b=d.div.childNodes.length-1;b>=0;b--){c=d.div.childNodes[b];if(c&&c.childNodes){for(h=c.childNodes.length-1;h>=0;h--){g=c.childNodes[h];try{c.removeChild(g)}catch(f){}}}if(c){try{d.div.removeChild(c)}catch(f){}}}}if(!d.div){a=document.getElementById(d.divID);if(a){d.div=a}}if(d.div&&d.div.parentNode){try{d.div.parentNode.removeChild(d.div)}catch(f){}d.div=null}},DONEfuncs:[],onDoneEmptyDiv:function(){var c=this,a,b;if(!c.winLoaded){return}if(c.WLfuncs&&c.WLfuncs.length&&c.WLfuncs[c.WLfuncs.length-1]!==null){return}for(a in c){b=c[a];if(b&&b.funcs){if(b.OTF==3){return}if(b.funcs.length&&b.funcs[b.funcs.length-1]!==null){return}}}for(a=0;a<c.DONEfuncs.length;a++){c.callArray(c.DONEfuncs)}
29561c.emptyDiv()},getWidth:function(c){if(c){var a=c.scrollWidth||c.offsetWidth,b=this;if(b.isNum(a)){return a}}return -1},getTagStatus:function(m,g,a,b){var c=this,f,k=m.span,l=c.getWidth(k),h=a.span,j=c.getWidth(h),d=g.span,i=c.getWidth(d);if(!k||!h||!d||!c.getDOMobj(m)){return -2}if(j<i||l<0||j<0||i<0||i<=c.pluginSize||c.pluginSize<1){return 0}if(l>=i){return -1}try{if(l==c.pluginSize&&(!c.isIE||c.getDOMobj(m).readyState==4)){if(!m.winLoaded&&c.winLoaded){return 1}if(m.winLoaded&&c.isNum(b)){if(!c.isNum(m.count)){m.count=b}if(b-m.count>=10){return 1}}}}catch(f){}return 0},getDOMobj:function(g,a){var f,d=this,c=g?g.span:0,b=c&&c.firstChild?1:0;try{if(b&&a){d.div.focus()}}catch(f){}return b?c.firstChild:null},setStyle:function(b,g){var f=b.style,a,d,c=this;if(f&&g){for(a=0;a<g.length;a=a+2){try{f[g[a]]=g[a+1]}catch(d){}}}},insertDivInBody:function(i,g){var f,c=this,h="pd33993399",b=null,d=g?window.top.document:window.document,a=d.getElementsByTagName("body")[0]||d.body;if(!a){try{d.write('<div id="'+h+'">.'+c.openTag+"/div>");b=d.getElementById(h)}catch(f){}}a=d.getElementsByTagName("body")[0]||d.body;if(a){a.insertBefore(i,a.firstChild);if(b){a.removeChild(b)}}},insertHTML:function(f,b,g,a,k){var l,m=document,j=this,p,o=m.createElement("span"),n,i;var c=["outlineStyle","none","borderStyle","none","padding","0px","margin","0px","visibility","visible"];var h="outline-style:none;border-style:none;padding:0px;margin:0px;visibility:visible;";if(!j.isDefined(a)){a=""}if(j.isString(f)&&(/[^\s]/).test(f)){f=f.toLowerCase().replace(/\s/g,"");p=j.openTag+f+' width="'+j.pluginSize+'" height="'+j.pluginSize+'" ';p+='style="'+h+'display:inline;" ';for(n=0;n<b.length;n=n+2){if(/[^\s]/.test(b[n+1])){p+=b[n]+'="'+b[n+1]+'" '}}p+=">";for(n=0;n<g.length;n=n+2){if(/[^\s]/.test(g[n+1])){p+=j.openTag+'param name="'+g[n]+'" value="'+g[n+1]+'" />'}}p+=a+j.openTag+"/"+f+">"}else{p=a}if(!j.div){i=m.getElementById(j.divID);if(i){j.div=i}else{j.div=m.createElement("div");j.div.id=j.divID}j.setStyle(j.div,c.concat(["width",j.divWidth+"px","height",(j.pluginSize+3)+"px","fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","block"]));if(!i){j.setStyle(j.div,["position","absolute","right","0px","top","0px"]);j.insertDivInBody(j.div)}}if(j.div&&j.div.parentNode){j.setStyle(o,c.concat(["fontSize",(j.pluginSize+3)+"px","lineHeight",(j.pluginSize+3)+"px","verticalAlign","baseline","display","inline"]));try{o.innerHTML=p}catch(l){};try{j.div.appendChild(o)}catch(l){};return{span:o,winLoaded:j.winLoaded,tagName:f,outerHTML:p}}return{span:null,winLoaded:j.winLoaded,tagName:"",outerHTML:p}},Plugins:{quicktime:{mimeType:["video/quicktime","application/x-quicktimeplayer","image/x-macpaint","image/x-quicktime"],progID:"QuickTimeCheckObject.QuickTimeCheck.1",progID0:"QuickTime.QuickTime",classID:"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",minIEver:7,HTML:'<param name="src" value="" /><param name="controller" value="false" />',getCodeBaseVersion:function(a){return'codebase="#version='+a+'"'},SEARCH:{min:0,max:0,match:0,digits:[16,128,128,0]},getVersion:function(c){var f=this,d=f.$,a=null,e=null,b;if(!d.isIE){if(d.hasMimeType(f.mimeType)){e=d.OS!=3?d.findNavPlugin("QuickTime.*Plug-?in",0):null;if(e&&e.name){a=d.getNum(e.name)}}}else{if(d.isStrNum(c)){b=c.split(d.splitNumRegx);if(b.length>3&&parseInt(b[3],10)>0){b[3]="9999"}c=b.join(",")}if(d.isStrNum(c)&&d.verIE>=f.minIEver&&f.canUseIsMin()>0){f.installed=f.isMin(c);f.getVersionDone=0;return}f.getVersionDone=1;if(!a&&d.verIE>=f.minIEver){a=f.CDBASE2VER(d.codebaseSearch(f))}if(!a){e=d.getAXO(f.progID);if(e&&e.QuickTimeVersion){a=e.QuickTimeVersion.toString(16);a=parseInt(a.charAt(0),16)+"."+parseInt(a.charAt(1),16)+"."+parseInt(a.charAt(2),16)}}}f.installed=a?1:(e?0:-1);f.version=d.formatNum(a,3)},cdbaseUpper:["7,60,0,0","0,0,0,0"],cdbaseLower:["7,50,0,0",null],cdbase2ver:[function(c,b){var a=b.split(c.$.splitNumRegx);return[a[0],a[1].charAt(0),a[1].charAt(1),a[2]].join(",")},null],CDBASE2VER:function(f){var e=this,c=e.$,b,a=e.cdbaseUpper,d=e.cdbaseLower;
29561if(f){f=c.formatNum(f);for(b=0;b<a.length;b++){if(a[b]&&c.compareNums(f,a[b])<0&&d[b]&&c.compareNums(f,d[b])>=0&&e.cdbase2ver[b]){return e.cdbase2ver[b](e,f)}}}return f},canUseIsMin:function(){var f=this,d=f.$,b,c=f.canUseIsMin,a=f.cdbaseUpper,e=f.cdbaseLower;if(!c.value){c.value=-1;for(b=0;b<a.length;b++){if(a[b]&&d.codebaseSearch(f,a[b])){c.value=1;break}if(e[b]&&d.codebaseSearch(f,e[b])){c.value=-1;break}}}f.SEARCH.match=c.value==1?1:0;return c.value},isMin:function(c){var b=this,a=b.$;return a.codebaseSearch(b,c)?0.7:-1}},flash:{mimeType:"application/x-shockwave-flash",progID:"ShockwaveFlash.ShockwaveFlash",classID:"clsid:D27CDB6E-AE6D-11CF-96B8-444553540000",getVersion:function(){var b=function(i){if(!i){return null}var e=/[\d][\d\,\.\s]*[rRdD]{0,1}[\d\,]*/.exec(i);return e?e[0].replace(/[rRdD\.]/g,",").replace(/\s/g,""):null};var j=this,g=j.$,k,h,l=null,c=null,a=null,f,m,d;if(!g.isIE){m=g.hasMimeType(j.mimeType);if(m){f=g.getDOMobj(g.insertHTML("object",["type",j.mimeType],[],"",j));try{l=g.getNum(f.GetVariable("$version"))}catch(k){}}if(!l){d=m?m.enabledPlugin:null;if(d&&d.description){l=b(d.description)}if(l){l=g.getPluginFileVersion(d,l)}}}else{for(h=15;h>2;h--){c=g.getAXO(j.progID+"."+h);if(c){a=h.toString();break}}if(!c){c=g.getAXO(j.progID)}if(a=="6"){try{c.AllowScriptAccess="always"}catch(k){return"6,0,21,0"}}try{l=b(c.GetVariable("$version"))}catch(k){}if(!l&&a){l=a}}j.installed=l?1:-1;j.version=g.formatNum(l);return true}},shockwave:{mimeType:"application/x-director",progID:"SWCtl.SWCtl",classID:"clsid:166B1BCA-3F9C-11CF-8075-444553540000",getVersion:function(){var a=null,b=null,g,f,d=this,c=d.$;if(!c.isIE){f=c.findNavPlugin("Shockwave\\s*for\\s*Director");if(f&&f.description&&c.hasMimeType(d.mimeType)){a=c.getNum(f.description)}if(a){a=c.getPluginFileVersion(f,a)}}else{try{b=c.getAXO(d.progID).ShockwaveVersion("")}catch(g){}if(c.isString(b)&&b.length>0){a=c.getNum(b)}else{if(c.getAXO(d.progID+".8")){a="8"}else{if(c.getAXO(d.progID+".7")){a="7"}else{if(c.getAXO(d.progID+".1")){a="6"}}}}}d.installed=a?1:-1;d.version=c.formatNum(a)}},zz:0}};PluginDetect.initScript();
29562
29563	var gArgCountErr='The "%%" function requires an even number of arguments.\nArguments should be in the form "atttributeName", "attributeValue", ...',gTagAttrs=null,gQTGeneratorVersion=1;function AC_QuickTimeVersion(){return gQTGeneratorVersion}function _QTComplain(a,b){b=b.replace("%%",a);alert(b)}function _QTAddAttribute(a,b,c){var d;d=gTagAttrs[a+b];null==d&&(d=gTagAttrs[b]);return null!=d?(0==b.indexOf(a)&&null==c&&(c=b.substring(a.length)),null==c&&(c=b),c+'="'+d+'" '):""}function _QTAddObjectAttr(a,b){if(0==a.indexOf("emb#"))return"";0==a.indexOf("obj#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("obj#",a,b)}function _QTAddEmbedAttr(a,b){if(0==a.indexOf("obj#"))return"";0==a.indexOf("emb#")&&null==b&&(b=a.substring(4));return _QTAddAttribute("emb#",a,b)}function _QTAddObjectParam(a,b){var c,d="",e=b?" />":">";-1==a.indexOf("emb#")&&(c=gTagAttrs["obj#"+a],null==c&&(c=gTagAttrs[a]),0==a.indexOf("obj#")&&(a=a.substring(4)),null!=c&&(d='  <param name="'+a+'" value="'+c+'"'+e+"\n"));return d}function _QTDeleteTagAttrs(){for(var a=0;a<arguments.length;a++){var b=arguments[a];delete gTagAttrs[b];delete gTagAttrs["emb#"+b];delete gTagAttrs["obj#"+b]}}function _QTGenerate(a,b,c){if(4>c.length||0!=c.length%2)return _QTComplain(a,gArgCountErr),"";gTagAttrs=[];gTagAttrs.src=c[0];gTagAttrs.width=c[1];gTagAttrs.height=c[2];gTagAttrs.classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B";gTagAttrs.pluginspage="http://www.apple.com/quicktime/download/";a=c[3];if(null==a||""==a)a="6,0,2,0";gTagAttrs.codebase="http://www.apple.com/qtactivex/qtplugin.cab#version="+a;for(var d,e=4;e<c.length;e+=2)d=c[e].toLowerCase(),a=c[e+1],"name"==d||"id"==d?gTagAttrs.name=a:gTagAttrs[d]=a;c="<object "+_QTAddObjectAttr("classid")+_QTAddObjectAttr("width")+_QTAddObjectAttr("height")+_QTAddObjectAttr("codebase")+_QTAddObjectAttr("name","id")+_QTAddObjectAttr("tabindex")+_QTAddObjectAttr("hspace")+_QTAddObjectAttr("vspace")+_QTAddObjectAttr("border")+_QTAddObjectAttr("align")+_QTAddObjectAttr("class")+_QTAddObjectAttr("title")+_QTAddObjectAttr("accesskey")+_QTAddObjectAttr("noexternaldata")+">\n"+_QTAddObjectParam("src",b);e="  <embed "+_QTAddEmbedAttr("src")+_QTAddEmbedAttr("width")+_QTAddEmbedAttr("height")+_QTAddEmbedAttr("pluginspage")+_QTAddEmbedAttr("name")+_QTAddEmbedAttr("align")+_QTAddEmbedAttr("tabindex");_QTDeleteTagAttrs("src","width","height","pluginspage","classid","codebase","name","tabindex","hspace","vspace","border","align","noexternaldata","class","title","accesskey");for(d in gTagAttrs)a=gTagAttrs[d],null!=a&&(e+=_QTAddEmbedAttr(d),c+=_QTAddObjectParam(d,b));return c+e+"> </embed>\n</object>"}function QT_GenerateOBJECTText(){return _QTGenerate("QT_GenerateOBJECTText",!1,arguments)};
29564
29565
29566	/*
29567		jQuery hashchange event v1.3
29568		https://github.com/cowboy/jquery-hashchange
29569		Copyright (c) 2010 "Cowboy" Ben Alman
29570		Dual licensed under the MIT and GPL licenses.
29571	*/
29572	(function(){function e(a){a=a||location.href;return"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var k=document,b,f=$.event.special,p=k.documentMode,m="oniLightBoxHashChange"in window&&(void 0===p||7<p);$.fn.iLightBoxHashChange=function(a){return a?this.bind("iLightBoxHashChange",a):this.trigger("iLightBoxHashChange")};$.fn.iLightBoxHashChange.delay=50;f.iLightBoxHashChange=$.extend(f.iLightBoxHashChange,{setup:function(){if(m)return!1;$(b.start)},teardown:function(){if(m)return!1;$(b.stop)}});b=function(){function a(){var c=
29573	e(),d=f(l);c!==l?(n(l=c,d),$(window).trigger("iLightBoxHashChange")):d!==l&&(location.href=location.href.replace(/#.*/,"")+d);g=setTimeout(a,$.fn.iLightBoxHashChange.delay)}var h={},g,l=e(),b=function(c){return c},n=b,f=b;h.start=function(){g||a()};h.stop=function(){g&&clearTimeout(g);g=void 0};browser.msie&&!m&&function(){var c,d;h.start=function(){c||(d=(d=$.fn.iLightBoxHashChange.src)&&d+e(),c=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||n(e());a()}).attr("src",d||
29574	"javascript:0").insertAfter("body")[0].contentWindow,k.onpropertychange=function(){try{"title"===event.propertyName&&(c.document.title=k.title)}catch(a){}})};h.stop=b;f=function(){return e(c.location.href)};n=function(a,d){var b=c.document,e=$.fn.iLightBoxHashChange.domain;
29574a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
29575
29576	if (!Array.prototype.filter) {
29577		Array.prototype.filter = function(fun /*, thisp */ ) {
29578			"use strict";
29579
29580			if (this == null)
29581				throw new TypeError();
29582
29583			var t = Object(this);
29584			var len = t.length >>> 0;
29585			if (typeof fun != "function")
29586				throw new TypeError();
29587
29588			var res = [];
29589			var thisp = arguments[1];
29590			for (var i = 0; i < len; i++) {
29591				if (i in t) {
29592					var val = t[i]; // in case fun mutates this
29593					if (fun.call(thisp, val, i, t))
29594						res.push(val);
29595				}
29596			}
29597
29598			return res;
29599		};
29600	}
29601
29602	if (!Array.prototype.indexOf) {
29603		Array.prototype.indexOf = function(searchElement, fromIndex) {
29604			var k;
29605
29606			if (this == null) {
29607				throw new TypeError('"this" is null or not defined');
29608			}
29609
29610			var O = Object(this);
29611
29612			var len = O.length >>> 0;
29613
29614			if (len === 0) {
29615				return -1;
29616			}
29617
29618			var n = +fromIndex || 0;
29619
29620			if (abs(n) === Infinity) {
29621				n = 0;
29622			}
29623
29624			if (n >= len) {
29625				return -1;
29626			}
29627
29628			k = max(n >= 0 ? n : len - abs(n), 0);
29629
29630			while (k < len) {
29631				var kValue;
29632				if (k in O && O[k] === searchElement) {
29633					return k;
29634				}
29635				k++;
29636			}
29637			return -1;
29638		};
29639	}
29640
29641	if (!Array.prototype.lastIndexOf) {
29642		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
29643			"use strict";
29644
29645			if (this == null)
29646				throw new TypeError();
29647
29648			var t = Object(this);
29649			var len = t.length >>> 0;
29650			if (len === 0)
29651				return -1;
29652
29653			var n = len;
29654			if (arguments.length > 1) {
29655				n = Number(arguments[1]);
29656				if (n != n)
29657					n = 0;
29658				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
29659					n = (n > 0 || -1) * floor(abs(n));
29660			}
29661
29662			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
29663
29664			for (; k >= 0; k--) {
29665				if (k in t && t[k] === searchElement)
29666					return k;
29667			}
29668			return -1;
29669		};
29670	}
29671})(jQuery, this);
29672
29673/*!
29674 * lightgallery | 2.5.0 | June 13th 2022
29675 * http://www.lightgalleryjs.com/
29676 * Copyright (c) 2020 Sachin Neravath;
29677 * @license GPLv3
29678 */
29679
29680(function (global, factory) {
29681	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
29682	typeof define === 'function' && define.amd ? define(factory) :
29683	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lightGallery = factory());
29684}(this, (function () { 'use strict';
29685
29686	/*! *****************************************************************************
29687	Copyright (c) Microsoft Corporation.
29688
29689	Permission to use, copy, modify, and/or distribute this software for any
29690	purpose with or without fee is hereby granted.
29691
29692	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
29693	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29694	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
29695	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
29696	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
29697	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
29698	PERFORMANCE OF THIS SOFTWARE.
29699	***************************************************************************** */
29700
29701	var __assign = function() {
29702		__assign = Object.assign || function __assign(t) {
29703			for (var s, i = 1, n = arguments.length; i < n; i++) {
29704				s = arguments[i];
29705				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
29706			}
29707			return t;
29708		};
29709		return __assign.apply(this, arguments);
29710	};
29711
29712	function __spreadArrays() {
29713		for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
29714		for (var r = Array(s), k = 0, i = 0; i < il; i++)
29715			for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
29716				r[k] = a[j];
29717		return r;
29718	}
29719
29720	/**
29721	 * List of lightGallery events
29722	 * All events should be documented here
29723	 * Below interfaces are used to build the website documentations
29724	 * */
29725	var lGEvents = {
29726		afterAppendSlide: 'lgAfterAppendSlide',
29727		init: 'lgInit',
29728		hasVideo: 'lgHasVideo',
29729		containerResize: 'lgContainerResize',
29730		updateSlides: 'lgUpdateSlides',
29731		afterAppendSubHtml: 'lgAfterAppendSubHtml',
29732		beforeOpen: 'lgBeforeOpen',
29733		afterOpen: 'lgAfterOpen',
29734		slideItemLoad: 'lgSlideItemLoad',
29735		beforeSlide: 'lgBeforeSlide',
29736		afterSlide: 'lgAfterSlide',
29737		posterClick: 'lgPosterClick',
29738		dragStart: 'lgDragStart',
29739		dragMove: 'lgDragMove',
29740		dragEnd: 'lgDragEnd',
29741		beforeNextSlide: 'lgBeforeNextSlide',
29742		beforePrevSlide: 'lgBeforePrevSlide',
29743		beforeClose: 'lgBeforeClose',
29744		afterClose: 'lgAfterClose',
29745		rotateLeft: 'lgRotateLeft',
29746		rotateRight: 'lgRotateRight',
29747		flipHorizontal: 'lgFlipHorizontal',
29748		flipVertical: 'lgFlipVertical',
29749		autoplay: 'lgAutoplay',
29750		autoplayStart: 'lgAutoplayStart',
29751		autoplayStop: 'lgAutoplayStop',
29752	};
29753
29754	var lightGalleryCoreSettings = {
29755		mode: 'lg-slide',
29756		easing: 'ease',
29757		speed: 400,
29758		licenseKey: '0000-0000-000-0000',
29759		height: '100%',
29760		width: '100%',
29761		addClass: '',
29762		startClass: 'lg-start-zoom',
29763		backdropDuration: 300,
29764		container: '',
29765		startAnimationDuration: 400,
29766		zoomFromOrigin: true,
29767		hideBarsDelay: 0,
29768		showBarsAfter: 10000,
29769		slideDelay: 0,
29770		supportLegacyBrowser: true,
29771		allowMediaOverlap: false,
29772		videoMaxSize: '1280-720',
29773		loadYouTubePoster: true,
29774		defaultCaptionHeight: 0,
29775		ariaLabelledby: '',
29776		ariaDescribedby: '',
29777		resetScrollPosition: true,
29778		hideScrollbar: false,
29779		closable: true,
29780		swipeToClose: true,
29781		closeOnTap: true,
29782		showCloseIcon: true,
29783		showMaximizeIcon: false,
29784		loop: true,
29785		escKey: true,
29786		keyPress: true,
29787		trapFocus: true,
29788		controls: true,
29789		slideEndAnimation: true,
29790		hideControlOnEnd: false,
vendor: 17,869 bytes, lines 29791-30410
29791		mousewheel: false,
29792		getCaptionFromTitleOrAlt: true,
29793		appendSubHtmlTo: '.lg-sub-html',
29794		subHtmlSelectorRelative: false,
29795		preload: 2,
29796		numberOfSlideItemsInDom: 10,
29797		selector: '',
29798		selectWithin: '',
29799		nextHtml: '',
29800		prevHtml: '',
29801		index: 0,
29802		iframeWidth: '100%',
29803		iframeHeight: '100%',
29804		iframeMaxWidth: '100%',
29805		iframeMaxHeight: '100%',
29806		download: true,
29807		counter: true,
29808		appendCounterTo: '.lg-toolbar',
29809		swipeThreshold: 50,
29810		enableSwipe: true,
29811		enableDrag: true,
29812		dynamic: false,
29813		dynamicEl: [],
29814		extraProps: [],
29815		exThumbImage: '',
29816		isMobile: undefined,
29817		mobileSettings: {
29818			controls: false,
29819			showCloseIcon: false,
29820			download: false,
29821		},
29822		plugins: [],
29823		strings: {
29824			closeGallery: 'Close gallery',
29825			toggleMaximize: 'Toggle maximize',
29826			previousSlide: 'Previous slide',
29827			nextSlide: 'Next slide',
29828			download: 'Download',
29829			playVideo: 'Play video',
29830		},
29831	};
29832
29833	function initLgPolyfills() {
29834		(function () {
29835			if (typeof window.CustomEvent === 'function')
29836				return false;
29837			function CustomEvent(event, params) {
29838				params = params || {
29839					bubbles: false,
29840					cancelable: false,
29841					detail: null,
29842				};
29843				var evt = document.createEvent('CustomEvent');
29844				evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
29845				return evt;
29846			}
29847			window.CustomEvent = CustomEvent;
29848		})();
29849		(function () {
29850			if (!Element.prototype.matches) {
29851				Element.prototype.matches =
29852					Element.prototype.msMatchesSelector ||
29853						Element.prototype.webkitMatchesSelector;
29854			}
29855		})();
29856	}
29857	var lgQuery = /** @class */ (function () {
29858		function lgQuery(selector) {
29859			this.cssVenderPrefixes = [
29860				'TransitionDuration',
29861				'TransitionTimingFunction',
29862				'Transform',
29863				'Transition',
29864			];
29865			this.selector = this._getSelector(selector);
29866			this.firstElement = this._getFirstEl();
29867			return this;
29868		}
29869		lgQuery.generateUUID = function () {
29870			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
29871				var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
29872				return v.toString(16);
29873			});
29874		};
29875		lgQuery.prototype._getSelector = function (selector, context) {
29876			if (context === void 0) { context = document; }
29877			if (typeof selector !== 'string') {
29878				return selector;
29879			}
29880			context = context || document;
29881			var fl = selector.substring(0, 1);
29882			if (fl === '#') {
29883				return context.querySelector(selector);
29884			}
29885			else {
29886				return context.querySelectorAll(selector);
29887			}
29888		};
29889		lgQuery.prototype._each = function (func) {
29890			if (!this.selector) {
29891				return this;
29892			}
29893			if (this.selector.length !== undefined) {
29894				[].forEach.call(this.selector, func);
29895			}
29896			else {
29897				func(this.selector, 0);
29898			}
29899			return this;
29900		};
29901		lgQuery.prototype._setCssVendorPrefix = function (el, cssProperty, value) {
29902			// prettier-ignore
29903			var property = cssProperty.replace(/-([a-z])/gi, function (s, group1) {
29904				return group1.toUpperCase();
29905			});
29906			if (this.cssVenderPrefixes.indexOf(property) !== -1) {
29907				el.style[property.charAt(0).toLowerCase() + property.slice(1)] = value;
29908				el.style['webkit' + property] = value;
29909				el.style['moz' + property] = value;
29910				el.style['ms' + property] = value;
29911				el.style['o' + property] = value;
29912			}
29913			else {
29914				el.style[property] = value;
29915			}
29916		};
29917		lgQuery.prototype._getFirstEl = function () {
29918			if (this.selector && this.selector.length !== undefined) {
29919				return this.selector[0];
29920			}
29921			else {
29922				return this.selector;
29923			}
29924		};
29925		lgQuery.prototype.isEventMatched = function (event, eventName) {
29926			var eventNamespace = eventName.split('.');
29927			return event
29928				.split('.')
29929				.filter(function (e) { return e; })
29930				.every(function (e) {
29931				return eventNamespace.indexOf(e) !== -1;
29932			});
29933		};
29934		lgQuery.prototype.attr = function (attr, value) {
29935			if (value === undefined) {
29936				if (!this.firstElement) {
29937					return '';
29938				}
29939				return this.firstElement.getAttribute(attr);
29940			}
29941			this._each(function (el) {
29942				el.setAttribute(attr, value);
29943			});
29944			return this;
29945		};
29946		lgQuery.prototype.find = function (selector) {
29947			return $LG(this._getSelector(selector, this.selector));
29948		};
29949		lgQuery.prototype.first = function () {
29950			if (this.selector && this.selector.length !== undefined) {
29951				return $LG(this.selector[0]);
29952			}
29953			else {
29954				return $LG(this.selector);
29955			}
29956		};
29957		lgQuery.prototype.eq = function (index) {
29958			return $LG(this.selector[index]);
29959		};
29960		lgQuery.prototype.parent = function () {
29961			return $LG(this.selector.parentElement);
29962		};
29963		lgQuery.prototype.get = function () {
29964			return this._getFirstEl();
29965		};
29966		lgQuery.prototype.removeAttr = function (attributes) {
29967			var attrs = attributes.split(' ');
29968			this._each(function (el) {
29969				attrs.forEach(function (attr) { return el.removeAttribute(attr); });
29970			});
29971			return this;
29972		};
29973		lgQuery.prototype.wrap = function (className) {
29974			if (!this.firstElement) {
29975				return this;
29976			}
29977			var wrapper = document.createElement('div');
29978			wrapper.className = className;
29979			this.firstElement.parentNode.insertBefore(wrapper, this.firstElement);
29980			this.firstElement.parentNode.removeChild(this.firstElement);
29981			wrapper.appendChild(this.firstElement);
29982			return this;
29983		};
29984		lgQuery.prototype.addClass = function (classNames) {
29985			if (classNames === void 0) { classNames = ''; }
29986			this._each(function (el) {
29987				// IE doesn't support multiple arguments
29988				classNames.split(' ').forEach(function (className) {
29989					if (className) {
29990						el.classList.add(className);
29991					}
29992				});
29993			});
29994			return this;
29995		};
29996		lgQuery.prototype.removeClass = function (classNames) {
29997			this._each(function (el) {
29998				// IE doesn't support multiple arguments
29999				classNames.split(' ').forEach(function (className) {
30000					if (className) {
30001						el.classList.remove(className);
30002					}
30003				});
30004			});
30005			return this;
30006		};
30007		lgQuery.prototype.hasClass = function (className) {
30008			if (!this.firstElement) {
30009				return false;
30010			}
30011			return this.firstElement.classList.contains(className);
30012		};
30013		lgQuery.prototype.hasAttribute = function (attribute) {
30014			if (!this.firstElement) {
30015				return false;
30016			}
30017			return this.firstElement.hasAttribute(attribute);
30018		};
30019		lgQuery.prototype.toggleClass = function (className) {
30020			if (!this.firstElement) {
30021				return this;
30022			}
30023			if (this.hasClass(className)) {
30024				this.removeClass(className);
30025			}
30026			else {
30027				this.addClass(className);
30028			}
30029			return this;
30030		};
30031		lgQuery.prototype.css = function (property, value) {
30032			var _this = this;
30033			this._each(function (el) {
30034				_this._setCssVendorPrefix(el, property, value);
30035			});
30036			return this;
30037		};
30038		// Need to pass separate namespaces for separate elements
30039		lgQuery.prototype.on = function (events, listener) {
30040			var _this = this;
30041			if (!this.selector) {
30042				return this;
30043			}
30044			events.split(' ').forEach(function (event) {
30045				if (!Array.isArray(lgQuery.eventListeners[event])) {
30046					lgQuery.eventListeners[event] = [];
30047				}
30048				lgQuery.eventListeners[event].push(listener);
30049				_this.selector.addEventListener(event.split('.')[0], listener);
30050			});
30051			return this;
30052		};
30053		// @todo - test this
30054		lgQuery.prototype.once = function (event, listener) {
30055			var _this = this;
30056			this.on(event, function () {
30057				_this.off(event);
30058				listener(event);
30059			});
30060			return this;
30061		};
30062		lgQuery.prototype.off = function (event) {
30063			var _this = this;
30064			if (!this.selector) {
30065				return this;
30066			}
30067			Object.keys(lgQuery.eventListeners).forEach(function (eventName) {
30068				if (_this.isEventMatched(event, eventName)) {
30069					lgQuery.eventListeners[eventName].forEach(function (listener) {
30070						_this.selector.removeEventListener(eventName.split('.')[0], listener);
30071					});
30072					lgQuery.eventListeners[eventName] = [];
30073				}
30074			});
30075			return this;
30076		};
30077		lgQuery.prototype.trigger = function (event, detail) {
30078			if (!this.firstElement) {
30079				return this;
30080			}
30081			var customEvent = new CustomEvent(event.split('.')[0], {
30082				detail: detail || null,
30083			});
30084			this.firstElement.dispatchEvent(customEvent);
30085			return this;
30086		};
30087		// Does not support IE
30088		lgQuery.prototype.load = function (url) {
30089			var _this = this;
30090			fetch(url)
30091				.then(function (res) { return res.text(); })
30092				.then(function (html) {
30093				_this.selector.innerHTML = html;
30094			});
30095			return this;
30096		};
30097		lgQuery.prototype.html = function (html) {
30098			if (html === undefined) {
30099				if (!this.firstElement) {
30100					return '';
30101				}
30102				return this.firstElement.innerHTML;
30103			}
30104			this._each(function (el) {
30105				el.innerHTML = html;
30106			});
30107			return this;
30108		};
30109		lgQuery.prototype.append = function (html) {
30110			this._each(function (el) {
30111				if (typeof html === 'string') {
30112					el.insertAdjacentHTML('beforeend', html);
30113				}
30114				else {
30115					el.appendChild(html);
30116				}
30117			});
30118			return this;
30119		};
30120		lgQuery.prototype.prepend = function (html) {
30121			this._each(function (el) {
30122				el.insertAdjacentHTML('afterbegin', html);
30123			});
30124			return this;
30125		};
30126		lgQuery.prototype.remove = function () {
30127			this._each(function (el) {
30128				el.parentNode.removeChild(el);
30129			});
30130			return this;
30131		};
30132		lgQuery.prototype.empty = function () {
30133			this._each(function (el) {
30134				el.innerHTML = '';
30135			});
30136			return this;
30137		};
30138		lgQuery.prototype.scrollTop = function (scrollTop) {
30139			if (scrollTop !== undefined) {
30140				document.body.scrollTop = scrollTop;
30141				document.documentElement.scrollTop = scrollTop;
30142				return this;
30143			}
30144			else {
30145				return (window.pageYOffset ||
30146					document.documentElement.scrollTop ||
30147					document.body.scrollTop ||
30148					0);
30149			}
30150		};
30151		lgQuery.prototype.scrollLeft = function (scrollLeft) {
30152			if (scrollLeft !== undefined) {
30153				document.body.scrollLeft = scrollLeft;
30154				document.documentElement.scrollLeft = scrollLeft;
30155				return this;
30156			}
30157			else {
30158				return (window.pageXOffset ||
30159					document.documentElement.scrollLeft ||
30160					document.body.scrollLeft ||
30161					0);
30162			}
30163		};
30164		lgQuery.prototype.offset = function () {
30165			if (!this.firstElement) {
30166				return {
30167					left: 0,
30168					top: 0,
30169				};
30170			}
30171			var rect = this.firstElement.getBoundingClientRect();
30172			var bodyMarginLeft = $LG('body').style().marginLeft;
30173			// Minus body margin - https://stackoverflow.com/questions/30711548/is-getboundingclientrect-left-returning-a-wrong-value
30174			return {
30175				left: rect.left - parseFloat(bodyMarginLeft) + this.scrollLeft(),
30176				top: rect.top + this.scrollTop(),
30177			};
30178		};
30179		lgQuery.prototype.style = function () {
30180			if (!this.firstElement) {
30181				return {};
30182			}
30183			return (this.firstElement.currentStyle ||
30184				window.getComputedStyle(this.firstElement));
30185		};
30186		// Width without padding and border even if box-sizing is used.
30187		lgQuery.prototype.width = function () {
30188			var style = this.style();
30189			return (this.firstElement.clientWidth -
30190				parseFloat(style.paddingLeft) -
30191				parseFloat(style.paddingRight));
30192		};
30193		// Height without padding and border even if box-sizing is used.
30194		lgQuery.prototype.height = function () {
30195			var style = this.style();
30196			return (this.firstElement.clientHeight -
30197				parseFloat(style.paddingTop) -
30198				parseFloat(style.paddingBottom));
30199		};
30200		lgQuery.eventListeners = {};
30201		return lgQuery;
30202	}());
30203	function $LG(selector) {
30204		initLgPolyfills();
30205		return new lgQuery(selector);
30206	}
30207
30208	var defaultDynamicOptions = [
30209		'src',
30210		'sources',
30211		'subHtml',
30212		'subHtmlUrl',
30213		'html',
30214		'video',
30215		'poster',
30216		'slideName',
30217		'responsive',
30218		'srcset',
30219		'sizes',
30220		'iframe',
30221		'downloadUrl',
30222		'download',
30223		'width',
30224		'facebookShareUrl',
30225		'tweetText',
30226		'iframeTitle',
30227		'twitterShareUrl',
30228		'pinterestShareUrl',
30229		'pinterestText',
30230		'fbHtml',
30231		'disqusIdentifier',
30232		'disqusUrl',
30233	];
30234	// Convert html data-attribute to camalcase
30235	function convertToData(attr) {
30236		// FInd a way for lgsize
30237		if (attr === 'href') {
30238			return 'src';
30239		}
30240		attr = attr.replace('data-', '');
30241		attr = attr.charAt(0).toLowerCase() + attr.slice(1);
30242		attr = attr.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
30243		return attr;
30244	}
30245	var utils = {
30246		/**
30247		 * get possible width and height from the lgSize attribute. Used for ZoomFromOrigin option
30248		 */
30249		//Uncode edit ##START##
30250		getSize: function (el, container, spacing, defaultLgSize, galleryItem) {
30251		// getSize: function (el, container, spacing, defaultLgSize) {
30252		//Uncode edit ##END##
30253			if (spacing === void 0) { spacing = 0; }
30254			var LGel = $LG(el);
30255			var lgSize = LGel.attr('data-lg-size') || defaultLgSize;
30256			//Uncode edit ##START##
30257			if ( typeof galleryItem.size && galleryItem.size != null ) {
30258				lgSize = galleryItem.size;
30259			}
30260			//Uncode edit ##END##
30261			if (!lgSize) {
30262				return;
30263			}
30264			var isResponsiveSizes = lgSize.split(',');
30265			// if at-least two viewport sizes are available
30266			if (isResponsiveSizes[1]) {
30267				var wWidth = window.innerWidth;
30268				for (var i = 0; i < isResponsiveSizes.length; i++) {
30269					var size_1 = isResponsiveSizes[i];
30270					var responsiveWidth = parseInt(size_1.split('-')[2], 10);
30271					if (responsiveWidth > wWidth) {
30272						lgSize = size_1;
30273						break;
30274					}
30275					// take last item as last option
30276					if (i === isResponsiveSizes.length - 1) {
30277						lgSize = size_1;
30278					}
30279				}
30280			}
30281			var size = lgSize.split('-');
30282			var width = parseInt(size[0], 10);
30283			var height = parseInt(size[1], 10);
30284			var cWidth = container.width();
30285			var cHeight = container.height() - spacing;
30286			var maxWidth = Math.min(cWidth, width);
30287			var maxHeight = Math.min(cHeight, height);
30288			var ratio = Math.min(maxWidth / width, maxHeight / height);
30289			return { width: width * ratio, height: height * ratio };
30290		},
30291		/**
30292		 * @desc Get transform value based on the imageSize. Used for ZoomFromOrigin option
30293		 * @param {jQuery Element}
30294		 * @returns {String} Transform CSS string
30295		 */
30296		getTransform: function (el, container, top, bottom, imageSize) {
30297			if (!imageSize) {
30298				return;
30299			}
30300			var LGel = $LG(el).find('img').first();
30301			if (!LGel.get()) {
30302				return;
30303			}
30304			var containerRect = container.get().getBoundingClientRect();
30305			var wWidth = containerRect.width;
30306			// using innerWidth to include mobile safari bottom bar
30307			var wHeight = container.height() - (top + bottom);
30308			var elWidth = LGel.width();
30309			var elHeight = LGel.height();
30310			var elStyle = LGel.style();
30311			var x = (wWidth - elWidth) / 2 -
30312				LGel.offset().left +
30313				(parseFloat(elStyle.paddingLeft) || 0) +
30314				(parseFloat(elStyle.borderLeft) || 0) +
30315				$LG(window).scrollLeft() +
30316				containerRect.left;
30317			var y = (wHeight - elHeight) / 2 -
30318				LGel.offset().top +
30319				(parseFloat(elStyle.paddingTop) || 0) +
30320				(parseFloat(elStyle.borderTop) || 0) +
30321				$LG(window).scrollTop() +
30322				top;
30323			var scX = elWidth / imageSize.width;
30324			var scY = elHeight / imageSize.height;
30325			var transform = 'translate3d(' +
30326				(x *= -1) +
30327				'px, ' +
30328				(y *= -1) +
30329				'px, 0) scale3d(' +
30330				scX +
30331				', ' +
30332				scY +
30333				', 1)';
30334			return transform;
30335		},
30336		getIframeMarkup: function (iframeWidth, iframeHeight, iframeMaxWidth, iframeMaxHeight, src, iframeTitle) {
30337			var title = iframeTitle ? 'title="' + iframeTitle + '"' : '';
30338			return "<div class=\"lg-video-cont lg-has-iframe\" style=\"width:" + iframeWidth + "; max-width:" + iframeMaxWidth + "; height: " + iframeHeight + "; max-height:" + iframeMaxHeight + "\">\n                    <iframe class=\"lg-object\" frameborder=\"0\" " + title + " src=\"" + src + "\"  allowfullscreen=\"true\"></iframe>\n                </div>";
30339		},
30340		getImgMarkup: function (index, src, altAttr, srcset, sizes, sources) {
30341			var srcsetAttr = srcset ? "srcset=\"" + srcset + "\"" : '';
30342			var sizesAttr = sizes ? "sizes=\"" + sizes + "\"" : '';
30343			var imgMarkup = "<img " + altAttr + " " + srcsetAttr + "  " + sizesAttr + " class=\"lg-object lg-image\" data-index=\"" + index + "\" src=\"" + src + "\" />";
30344			var sourceTag = '';
30345			if (sources) {
30346				var sourceObj = typeof sources === 'string' ? JSON.parse(sources) : sources;
30347				sourceTag = sourceObj.map(function (source) {
30348					var attrs = '';
30349					Object.keys(source).forEach(function (key) {
30350						// Do not remove the first space as it is required to separate the attributes
30351						attrs += " " + key + "=\"" + source[key] + "\"";
30352					});
30353					return "<source " + attrs + "></source>";
30354				});
30355			}
30356			return "" + sourceTag + imgMarkup;
30357		},
30358		// Get src from responsive src
30359		getResponsiveSrc: function (srcItms) {
30360			var rsWidth = [];
30361			var rsSrc = [];
30362			var src = '';
30363			for (var i = 0; i < srcItms.length; i++) {
30364				var _src = srcItms[i].split(' ');
30365				// Manage empty space
30366				if (_src[0] === '') {
30367					_src.splice(0, 1);
30368				}
30369				rsSrc.push(_src[0]);
30370				rsWidth.push(_src[1]);
30371			}
30372			var wWidth = window.innerWidth;
30373			for (var j = 0; j < rsWidth.length; j++) {
30374				if (parseInt(rsWidth[j], 10) > wWidth) {
30375					src = rsSrc[j];
30376					break;
30377				}
30378			}
30379			return src;
30380		},
30381		isImageLoaded: function (img) {
30382			if (!img)
30383				return false;
30384			// During the onload event, IE correctly identifies any images that
30385			// weren’t downloaded as not complete. Others should too. Gecko-based
30386			// browsers act like NS4 in that they report this incorrectly.
30387			if (!img.complete) {
30388				return false;
30389			}
30390			// However, they do have two very useful properties: naturalWidth and
30391			// naturalHeight. These give the true size of the image. If it failed
30392			// to load, either of these should be zero.
30393			if (img.naturalWidth === 0) {
30394				return false;
30395			}
30396			// No other way of checking: assume it’s ok.
30397			return true;
30398		},
30399		getVideoPosterMarkup: function (_poster, dummyImg, videoContStyle, playVideoString, _isVideo) {
30400			var videoClass = '';
30401			if (_isVideo && _isVideo.youtube) {
30402				videoClass = 'lg-has-youtube';
30403			}
30404			else if (_isVideo && _isVideo.vimeo) {
30405				videoClass = 'lg-has-vimeo';
30406			}
30407			else {
30408				videoClass = 'lg-has-html5';
30409			}
30410			return "<div class=\"lg-video-cont " + videoClass + "\" style=\"" + videoContStyle + "\">\n                <div class=\"lg-video-play-button\">
30410\n                <svg\n                    viewBox=\"0 0 20 20\"\n                    preserveAspectRatio=\"xMidYMid\"\n                    focusable=\"false\"\n                    aria-labelledby=\"" + playVideoString + "\"\n                    role=\"img\"\n                    class=\"lg-video-play-icon\"\n                >\n                    <title>" + playVideoString + "</title>\n                    <polygon class=\"lg-video-play-icon-inner\" points=\"1,0 20,10 1,20\"></polygon>\n                </svg>\n                <svg class=\"lg-video-play-icon-bg\" viewBox=\"0 0 50 50\" focusable=\"false\">\n                    <circle cx=\"50%\" cy=\"50%\" r=\"20\"></circle></svg>\n                <svg class=\"lg-video-play-icon-circle\" viewBox=\"0 0 50 50\" focusable=\"false\">\n                    <circle cx=\"50%\" cy=\"50%\" r=\"20\"></circle>\n                </svg>\n            </div>\n            " + (dummyImg || '') + "\n            <img class=\"lg-object lg-video-poster\" src=\"" + _poster + "\" />\n        </div>";
30411		},
30412		getFocusableElements: function (container) {
30413			var elements = container.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])');
30414			var visibleElements = [].filter.call(elements, function (element) {
30415				var style = window.getComputedStyle(element);
30416				return style.display !== 'none' && style.visibility !== 'hidden';
30417			});
30418			return visibleElements;
30419		},
30420		/**
30421		 * @desc Create dynamic elements array from gallery items when dynamic option is false
30422		 * It helps to avoid frequent DOM interaction
30423		 * and avoid multiple checks for dynamic elments
30424		 *
30425		 * @returns {Array} dynamicEl
30426		 */
30427		getDynamicOptions: function (items, extraProps, getCaptionFromTitleOrAlt, exThumbImage) {
30428			var dynamicElements = [];
30429			var availableDynamicOptions = __spreadArrays(defaultDynamicOptions, extraProps);
30430			[].forEach.call(items, function (item) {
30431				var dynamicEl = {};
30432				for (var i = 0; i < item.attributes.length; i++) {
30433					var attr = item.attributes[i];
30434					if (attr.specified) {
30435						var dynamicAttr = convertToData(attr.name);
30436						var label = '';
30437						if (availableDynamicOptions.indexOf(dynamicAttr) > -1) {
30438							label = dynamicAttr;
30439						}
30440						if (label) {
30441							dynamicEl[label] = attr.value;
30442						}
30443					}
30444				}
30445				var currentItem = $LG(item);
30446				var alt = currentItem.find('img').first().attr('alt') || currentItem.attr('data-alt');
30447				var title = currentItem.attr('title');
30448				//Uncode edit ##START##
30449				// var thumb = exThumbImage
30450				var thumb = exThumbImage && currentItem.attr(exThumbImage)
30451				//Uncode edit ##END##
30452					? currentItem.attr(exThumbImage)
30453					: currentItem.find('img').first().attr('src');
30454				dynamicEl.thumb = thumb;
30455				//Uncode edit ##START##
30456				if (getCaptionFromTitleOrAlt && !dynamicEl.subHtml) {
30457					// dynamicEl.subHtml = title || alt || '';
30458					dynamicEl.subHtml = title || '';
30459				}
30460				// dynamicEl.alt = alt || title || '';
30461				dynamicEl.alt = alt || title;
30462				var inlineType = currentItem.attr('data-type');
30463				dynamicEl.type = inlineType;
30464				//Uncode edit ##END##
30465				dynamicElements.push(dynamicEl);
30466			});
30467			return dynamicElements;
30468		},
30469		isMobile: function () {
30470			return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
30471		},
30472		/**
30473		 * @desc Check the given src is video
30474		 * @param {String} src
30475		 * @return {Object} video type
30476		 * Ex:{ youtube  :  ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
30477		 *
30478		 * @todo - this information can be moved to dynamicEl to avoid frequent calls
30479		 */
30480		isVideo: function (src, isHTML5VIdeo, index) {
30481			if (!src || src.match(/\.(mp4|m4v|ogg|webm)$/) ) {
30482				if (isHTML5VIdeo) {
30483					return {
30484						html5: true,
30485					};
30486				}
30487				else {
30488					console.warn('lightGallery :- data-src is not provided on slide item ' +
30489						(index + 1) +
30490						'. Please make sure the selector property is properly configured. More info - https://www.lightgalleryjs.com/demos/html-markup/');
30491					return;
30492				}
30493			}
30494			var youtube = src.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com|be-nocookie\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)([\&|?][\S]*)*/i);
30495			var vimeo = src.match(/\/\/(?:www\.)?(?:player\.)?vimeo.com\/(?:video\/)?([0-9a-z\-_]+)(.*)?/i);
30496			var wistia = src.match(/https?:\/\/(.+)?(wistia\.com|wi\.st)\/(medias|embed)\/([0-9a-z\-_]+)(.*)/);
30497			if (youtube) {
30498				return {
30499					youtube: youtube,
30500				};
30501			}
30502			else if (vimeo) {
30503				return {
30504					vimeo: vimeo,
30505				};
30506			}
30507			else if (wistia) {
30508				return {
30509					wistia: wistia,
30510				};
30511			}
30512		},
30513	};
30514
30515	// @ref - https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio
30516	// @ref - https://2ality.com/2017/04/setting-up-multi-platform-packages.html
30517	// Unique id for each gallery
30518	var lgId = 0;
30519	var LightGallery = /** @class */ (function () {
30520		function LightGallery(element, options) {
30521			this.lgOpened = false;
vendor: 26,259 bytes, lines 30522-31201
30522			this.index = 0;
30523			// lightGallery modules
30524			this.plugins = [];
30525			// false when lightGallery load first slide content;
30526			this.lGalleryOn = false;
30527			// True when a slide animation is in progress
30528			this.lgBusy = false;
30529			this.currentItemsInDom = [];
30530			// Scroll top value before lightGallery is opened
30531			this.prevScrollTop = 0;
30532			this.bodyPaddingRight = 0;
30533			this.isDummyImageRemoved = false;
30534			this.dragOrSwipeEnabled = false;
30535			this.mediaContainerPosition = {
30536				top: 0,
30537				bottom: 0,
30538			};
30539			if (!element) {
30540				return this;
30541			}
30542			lgId++;
30543			this.lgId = lgId;
30544			this.el = element;
30545			this.LGel = $LG(element);
30546			this.generateSettings(options);
30547			this.buildModules();
30548			// When using dynamic mode, ensure dynamicEl is an array
30549			if (this.settings.dynamic &&
30550				this.settings.dynamicEl !== undefined &&
30551				!Array.isArray(this.settings.dynamicEl)) {
30552				throw 'When using dynamic mode, you must also define dynamicEl as an Array.';
30553			}
30554			this.galleryItems = this.getItems();
30555			this.normalizeSettings();
30556			// Gallery items
30557			this.init();
30558			//Uncode edit ##START##
30559			// this.validateLicense();
30560			//Uncode edit ##END##
30561			return this;
30562		}
30563		LightGallery.prototype.generateSettings = function (options) {
30564			// lightGallery settings
30565			this.settings = __assign(__assign({}, lightGalleryCoreSettings), options);
30566			if (this.settings.isMobile &&
30567				typeof this.settings.isMobile === 'function'
30568				? this.settings.isMobile()
30569				: utils.isMobile()) {
30570				var mobileSettings = __assign(__assign({}, this.settings.mobileSettings), this.settings.mobileSettings);
30571				this.settings = __assign(__assign({}, this.settings), mobileSettings);
30572			}
30573		};
30574		LightGallery.prototype.normalizeSettings = function () {
30575			if (this.settings.slideEndAnimation) {
30576				this.settings.hideControlOnEnd = false;
30577			}
30578			if (!this.settings.closable) {
30579				this.settings.swipeToClose = false;
30580			}
30581			// And reset it on close to get the correct value next time
30582			this.zoomFromOrigin = this.settings.zoomFromOrigin;
30583			// At the moment, Zoom from image doesn't support dynamic options
30584			// @todo add zoomFromOrigin support for dynamic images
30585			if (this.settings.dynamic) {
30586				this.zoomFromOrigin = false;
30587			}
30588			if (!this.settings.container) {
30589				this.settings.container = document.body;
30590			}
30591			// settings.preload should not be grater than $item.length
30592			this.settings.preload = Math.min(this.settings.preload, this.galleryItems.length);
30593		};
30594		LightGallery.prototype.init = function () {
30595			var _this = this;
30596			this.addSlideVideoInfo(this.galleryItems);
30597			this.buildStructure();
30598			this.LGel.trigger(lGEvents.init, {
30599				instance: this,
30600			});
30601			if (this.settings.keyPress) {
30602				this.keyPress();
30603			}
30604			setTimeout(function () {
30605				_this.enableDrag();
30606				_this.enableSwipe();
30607				_this.triggerPosterClick();
30608			}, 50);
30609			this.arrow();
30610			if (this.settings.mousewheel) {
30611				this.mousewheel();
30612			}
30613			if (!this.settings.dynamic) {
30614				this.openGalleryOnItemClick();
30615			}
30616		};
30617		LightGallery.prototype.openGalleryOnItemClick = function () {
30618			var _this = this;
30619			var _loop_1 = function (index) {
30620				var element = this_1.items[index];
30621				var $element = $LG(element);
30622				// Using different namespace for click because click event should not unbind if selector is same object('this')
30623				// @todo manage all event listners - should have namespace that represent element
30624				var uuid = lgQuery.generateUUID();
30625				$element
30626					.attr('data-lg-id', uuid)
30627					.on("click.lgcustom-item-" + uuid, function (e) {
30628					e.preventDefault();
30629					var currentItemIndex = _this.settings.index || index;
30630					_this.openGallery(currentItemIndex, element);
30631				});
30632			};
30633			var this_1 = this;
30634			// Using for loop instead of using bubbling as the items can be any html element.
30635			for (var index = 0; index < this.items.length; index++) {
30636				_loop_1(index);
30637			}
30638		};
30639		/**
30640		 * Module constructor
30641		 * Modules are build incrementally.
30642		 * Gallery should be opened only once all the modules are initialized.
30643		 * use moduleBuildTimeout to make sure this
30644		 */
30645		LightGallery.prototype.buildModules = function () {
30646			var _this = this;
30647			this.settings.plugins.forEach(function (plugin) {
30648				_this.plugins.push(new plugin(_this, $LG));
30649			});
30650		};
30651		LightGallery.prototype.validateLicense = function () {
30652			if (!this.settings.licenseKey) {
30653				console.warn('Please provide a valid license key');
30654			}
30655			else if (this.settings.licenseKey === '0000-0000-000-0000') {
30656				console.warn("lightGallery: " + this.settings.licenseKey + " license key is not valid for production use");
30657			}
30658		};
30659		LightGallery.prototype.getSlideItem = function (index) {
30660			return $LG(this.getSlideItemId(index));
30661		};
30662		LightGallery.prototype.getSlideItemId = function (index) {
30663			return "#lg-item-" + this.lgId + "-" + index;
30664		};
30665		LightGallery.prototype.getIdName = function (id) {
30666			return id + "-" + this.lgId;
30667		};
30668		LightGallery.prototype.getElementById = function (id) {
30669			return $LG("#" + this.getIdName(id));
30670		};
30671		LightGallery.prototype.manageSingleSlideClassName = function () {
30672			if (this.galleryItems.length < 2) {
30673				this.outer.addClass('lg-single-item');
30674			}
30675			else {
30676				this.outer.removeClass('lg-single-item');
30677			}
30678		};
30679		LightGallery.prototype.buildStructure = function () {
30680			var _this = this;
30681			var container = this.$container && this.$container.get();
30682			if (container) {
30683				return;
30684			}
30685			var controls = '';
30686			var subHtmlCont = '';
30687			// Create controls
30688			if (this.settings.controls) {
30689				controls = "<button type=\"button\" id=\"" + this.getIdName('lg-prev') + "\" aria-label=\"" + this.settings.strings['previousSlide'] + "\" class=\"lg-prev lg-icon\"> " + this.settings.prevHtml + " </button>\n                <button type=\"button\" id=\"" + this.getIdName('lg-next') + "\" aria-label=\"" + this.settings.strings['nextSlide'] + "\" class=\"lg-next lg-icon\"> " + this.settings.nextHtml + " </button>";
30690			}
30691			if (this.settings.appendSubHtmlTo !== '.lg-item') {
30692				subHtmlCont =
30693					'<div class="lg-sub-html" role="status" aria-live="polite"></div>';
30694			}
30695			var addClasses = '';
30696			if (this.settings.allowMediaOverlap) {
30697				// Do not remove space before last single quote
30698				addClasses += 'lg-media-overlap ';
30699			}
30700			var ariaLabelledby = this.settings.ariaLabelledby
30701				? 'aria-labelledby="' + this.settings.ariaLabelledby + '"'
30702				: '';
30703			var ariaDescribedby = this.settings.ariaDescribedby
30704				? 'aria-describedby="' + this.settings.ariaDescribedby + '"'
30705				: '';
30706			var containerClassName = "lg-container " + this.settings.addClass + " " + (document.body !== this.settings.container ? 'lg-inline' : '');
30707			var closeIcon = this.settings.closable && this.settings.showCloseIcon
30708				? "<button type=\"button\" aria-label=\"" + this.settings.strings['closeGallery'] + "\" id=\"" + this.getIdName('lg-close') + "\" class=\"lg-close lg-icon\"></button>"
30709				: '';
30710			var maximizeIcon = this.settings.showMaximizeIcon
30711				? "<button type=\"button\" aria-label=\"" + this.settings.strings['toggleMaximize'] + "\" id=\"" + this.getIdName('lg-maximize') + "\" class=\"lg-maximize lg-icon\"></button>"
30712				: '';
30713			var template = "\n        <div class=\"" + containerClassName + "\" id=\"" + this.getIdName('lg-container') + "\" tabindex=\"-1\" aria-modal=\"true\" " + ariaLabelledby + " " + ariaDescribedby + " role=\"dialog\"\n        >\n            <div id=\"" + this.getIdName('lg-backdrop') + "\" class=\"lg-backdrop\"></div>\n\n            <div id=\"" + this.getIdName('lg-outer') + "\" class=\"lg-outer lg-use-css3 lg-css3 lg-hide-items " + addClasses + " \">\n\n              <div id=\"" + this.getIdName('lg-content') + "\" class=\"lg-content\">\n                <div id=\"" + this.getIdName('lg-inner') + "\" class=\"lg-inner\">\n                </div>\n                " + controls + "\n              </div>\n                <div id=\"" + this.getIdName('lg-toolbar') + "\" class=\"lg-toolbar lg-group\">\n                    " + maximizeIcon + "\n                    " + closeIcon + "\n                    </div>\n                    " + (this.settings.appendSubHtmlTo === '.lg-outer'
30714				? subHtmlCont
30715				: '') + "\n                <div id=\"" + this.getIdName('lg-components') + "\" class=\"lg-components\">\n                    " + (this.settings.appendSubHtmlTo === '.lg-sub-html'
30716				? subHtmlCont
30717				: '') + "\n                </div>\n            </div>\n        </div>\n        ";
30718			$LG(this.settings.container).append(template);
30719			if (document.body !== this.settings.container) {
30720				$LG(this.settings.container).css('position', 'relative');
30721			}
30722			this.outer = this.getElementById('lg-outer');
30723			this.$lgComponents = this.getElementById('lg-components');
30724			this.$backdrop = this.getElementById('lg-backdrop');
30725			this.$container = this.getElementById('lg-container');
30726			this.$inner = this.getElementById('lg-inner');
30727			this.$content = this.getElementById('lg-content');
30728			this.$toolbar = this.getElementById('lg-toolbar');
30729			this.$backdrop.css('transition-duration', this.settings.backdropDuration + 'ms');
30730			var outerClassNames = this.settings.mode + " ";
30731			this.manageSingleSlideClassName();
30732			if (this.settings.enableDrag) {
30733				outerClassNames += 'lg-grab ';
30734			}
30735			this.outer.addClass(outerClassNames);
30736			this.$inner.css('transition-timing-function', this.settings.easing);
30737			this.$inner.css('transition-duration', this.settings.speed + 'ms');
30738			if (this.settings.download) {
30739				this.$toolbar.append("<a id=\"" + this.getIdName('lg-download') + "\" target=\"_blank\" rel=\"noopener\" aria-label=\"" + this.settings.strings['download'] + "\" download class=\"lg-download lg-icon\"></a>");
30740			}
30741			this.counter();
30742			$LG(window).on("resize.lg.global" + this.lgId + " orientationchange.lg.global" + this.lgId, function () {
30743				_this.refreshOnResize();
30744			});
30745			this.hideBars();
30746			this.manageCloseGallery();
30747			this.toggleMaximize();
30748			this.initModules();
30749		};
30750		LightGallery.prototype.refreshOnResize = function () {
30751			if (this.lgOpened) {
30752				var currentGalleryItem = this.galleryItems[this.index];
30753				var __slideVideoInfo = currentGalleryItem.__slideVideoInfo;
30754				this.mediaContainerPosition = this.getMediaContainerPosition();
30755				var _a = this.mediaContainerPosition, top_1 = _a.top, bottom = _a.bottom;
30756				//Uncode edit ##START##
30757				this.currentImageSize = utils.getSize(this.items[this.index], this.outer, top_1 + bottom, __slideVideoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]);
30758				// this.currentImageSize = utils.getSize(this.items[this.index], this.outer, top_1 + bottom, __slideVideoInfo && this.settings.videoMaxSize);
30759				//Uncode edit ##END##
30760				if (__slideVideoInfo) {
30761					this.resizeVideoSlide(this.index, this.currentImageSize);
30762				}
30763				if (this.zoomFromOrigin && !this.isDummyImageRemoved) {
30764					var imgStyle = this.getDummyImgStyles(this.currentImageSize);
30765					this.outer
30766						.find('.lg-current .lg-dummy-img')
30767						.first()
30768						.attr('style', imgStyle);
30769				}
30770				this.LGel.trigger(lGEvents.containerResize);
30771			}
30772		};
30773		LightGallery.prototype.resizeVideoSlide = function (index, imageSize) {
30774			var lgVideoStyle = this.getVideoContStyle(imageSize);
30775			var currentSlide = this.getSlideItem(index);
30776			currentSlide.find('.lg-video-cont').attr('style', lgVideoStyle);
30777		};
30778		/**
30779		 * Update slides dynamically.
30780		 * Add, edit or delete slides dynamically when lightGallery is opened.
30781		 * Modify the current gallery items and pass it via updateSlides method
30782		 * @note
30783		 * - Do not mutate existing lightGallery items directly.
30784		 * - Always pass new list of gallery items
30785		 * - You need to take care of thumbnails outside the gallery if any
30786		 * - user this method only if you want to update slides when the gallery is opened. Otherwise, use `refresh()` method.
30787		 * @param items Gallery items
30788		 * @param index After the update operation, which slide gallery should navigate to
30789		 * @category lGPublicMethods
30790		 * @example
30791		 * const plugin = lightGallery();
30792		 *
30793		 * // Adding slides dynamically
30794		 * let galleryItems = [
30795		 * // Access existing lightGallery items
30796		 * // galleryItems are automatically generated internally from the gallery HTML markup
30797		 * // or directly from galleryItems when dynamic gallery is used
30798		 *   ...plugin.galleryItems,
30799		 *     ...[
30800		 *       {
30801		 *         src: 'img/img-1.png',
30802		 *           thumb: 'img/thumb1.png',
30803		 *         },
30804		 *     ],
30805		 *   ];
30806		 *   plugin.updateSlides(
30807		 *     galleryItems,
30808		 *     plugin.index,
30809		 *   );
30810		 *
30811		 *
30812		 * // Remove slides dynamically
30813		 * galleryItems = JSON.parse(
30814		 *   JSON.stringify(updateSlideInstance.galleryItems),
30815		 * );
30816		 * galleryItems.shift();
30817		 * updateSlideInstance.updateSlides(galleryItems, 1);
30818		 * @see <a href="/demos/update-slides/">Demo</a>
30819		 */
30820		LightGallery.prototype.updateSlides = function (items, index) {
30821			if (this.index > items.length - 1) {
30822				this.index = items.length - 1;
30823			}
30824			if (items.length === 1) {
30825				this.index = 0;
30826			}
30827			if (!items.length) {
30828				this.closeGallery();
30829				return;
30830			}
30831			var currentSrc = this.galleryItems[index].src;
30832			this.galleryItems = items;
30833			this.updateControls();
30834			this.$inner.empty();
30835			this.currentItemsInDom = [];
30836			var _index = 0;
30837			// Find the current index based on source value of the slide
30838			this.galleryItems.some(function (galleryItem, itemIndex) {
30839				if (galleryItem.src === currentSrc) {
30840					_index = itemIndex;
30841					return true;
30842				}
30843				return false;
30844			});
30845			this.currentItemsInDom = this.organizeSlideItems(_index, -1);
30846			this.loadContent(_index, true);
30847			this.getSlideItem(_index).addClass('lg-current');
30848			this.index = _index;
30849			this.updateCurrentCounter(_index);
30850			this.LGel.trigger(lGEvents.updateSlides);
30851		};
30852		// Get gallery items based on multiple conditions
30853		LightGallery.prototype.getItems = function () {
30854			// Gallery items
30855			this.items = [];
30856			if (!this.settings.dynamic) {
30857				if (this.settings.selector === 'this') {
30858					this.items.push(this.el);
30859				}
30860				else if (this.settings.selector) {
30861					if (typeof this.settings.selector === 'string') {
30862						if (this.settings.selectWithin) {
30863							var selectWithin = $LG(this.settings.selectWithin);
30864							this.items = selectWithin
30865								.find(this.settings.selector)
30866								.get();
30867						}
30868						else {
30869							this.items = this.el.querySelectorAll(this.settings.selector);
30870						}
30871					}
30872					else {
30873						this.items = this.settings.selector;
30874					}
30875				}
30876				else {
30877					this.items = this.el.children;
30878				}
30879				return utils.getDynamicOptions(this.items, this.settings.extraProps, this.settings.getCaptionFromTitleOrAlt, this.settings.exThumbImage);
30880			}
30881			else {
30882				return this.settings.dynamicEl || [];
30883			}
30884		};
30885		LightGallery.prototype.shouldHideScrollbar = function () {
30886			return (this.settings.hideScrollbar &&
30887				document.body === this.settings.container);
30888		};
30889		LightGallery.prototype.hideScrollbar = function () {
30890			if (!this.shouldHideScrollbar()) {
30891				return;
30892			}
30893			this.bodyPaddingRight = parseFloat($LG('body').style().paddingRight);
30894			var bodyRect = document.documentElement.getBoundingClientRect();
30895			var scrollbarWidth = window.innerWidth - bodyRect.width;
30896			$LG(document.body).css('padding-right', scrollbarWidth + this.bodyPaddingRight + 'px');
30897			$LG(document.body).addClass('lg-overlay-open');
30898		};
30899		LightGallery.prototype.resetScrollBar = function () {
30900			if (!this.shouldHideScrollbar()) {
30901				return;
30902			}
30903			$LG(document.body).css('padding-right', this.bodyPaddingRight + 'px');
30904			$LG(document.body).removeClass('lg-overlay-open');
30905		};
30906		/**
30907		 * Open lightGallery.
30908		 * Open gallery with specific slide by passing index of the slide as parameter.
30909		 * @category lGPublicMethods
30910		 * @param {Number} index  - index of the slide
30911		 * @param {HTMLElement} element - Which image lightGallery should zoom from
30912		 *
30913		 * @example
30914		 * const $dynamicGallery = document.getElementById('dynamic-gallery-demo');
30915		 * const dynamicGallery = lightGallery($dynamicGallery, {
30916		 *     dynamic: true,
30917		 *     dynamicEl: [
30918		 *         {
30919		 *              src: 'img/1.jpg',
30920		 *              thumb: 'img/thumb-1.jpg',
30921		 *              subHtml: '<h4>Image 1 title</h4><p>Image 1 descriptions.</p>',
30922		 *         },
30923		 *         ...
30924		 *     ],
30925		 * });
30926		 * $dynamicGallery.addEventListener('click', function () {
30927		 *     // Starts with third item.(Optional).
30928		 *     // This is useful if you want use dynamic mode with
30929		 *     // custom thumbnails (thumbnails outside gallery),
30930		 *     dynamicGallery.openGallery(2);
30931		 * });
30932		 *
30933		 */
30934		LightGallery.prototype.openGallery = function (index, element) {
30935			var _this = this;
30936			if (index === void 0) { index = this.settings.index; }
30937			// prevent accidental double execution
30938			if (this.lgOpened)
30939				return;
30940			this.lgOpened = true;
30941			this.outer.removeClass('lg-hide-items');
30942			this.hideScrollbar();
30943			// Add display block, but still has opacity 0
30944			this.$container.addClass('lg-show');
30945			var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, index);
30946			this.currentItemsInDom = itemsToBeInsertedToDom;
30947			var items = '';
30948			itemsToBeInsertedToDom.forEach(function (item) {
30949				items = items + ("<div id=\"" + item + "\" class=\"lg-item\"></div>");
30950			});
30951			this.$inner.append(items);
30952			this.addHtml(index);
30953			var transform = '';
30954			this.mediaContainerPosition = this.getMediaContainerPosition();
30955			var _a = this.mediaContainerPosition, top = _a.top, bottom = _a.bottom;
30956			if (!this.settings.allowMediaOverlap) {
30957				this.setMediaContainerPosition(top, bottom);
30958			}
30959			var __slideVideoInfo = this.galleryItems[index].__slideVideoInfo;
30960			if (this.zoomFromOrigin && element) {
30961				//Uncode edit ##START##
30962				this.currentImageSize = utils.getSize(element, this.outer, top + bottom, __slideVideoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]);
30963				// this.currentImageSize = utils.getSize(element, this.outer, top + bottom, __slideVideoInfo && this.settings.videoMaxSize);
30964				//Uncode edit ##END##
30965				transform = utils.getTransform(element, this.outer, top, bottom, this.currentImageSize);
30966			}
30967			if (!this.zoomFromOrigin || !transform) {
30968				this.outer.addClass(this.settings.startClass);
30969				this.getSlideItem(index).removeClass('lg-complete');
30970			}
30971			var timeout = this.settings.zoomFromOrigin
30972				? 100
30973				: this.settings.backdropDuration;
30974			setTimeout(function () {
30975				_this.outer.addClass('lg-components-open');
30976			}, timeout);
30977			this.index = index;
30978			//Uncode edit ##START##
30979			// this.LGel.trigger(lGEvents.beforeOpen);
30980			this.LGel.trigger(lGEvents.beforeOpen, {
30981				galleryItems: this.galleryItems,
30982				items: this.items,
30983				outer: this.outer,
30984			});
30985			//Uncode edit ##END##
30986			// add class lg-current to remove initial transition
30987			this.getSlideItem(index).addClass('lg-current');
30988			this.lGalleryOn = false;
30989			// Store the current scroll top value to scroll back after closing the gallery..
30990			this.prevScrollTop = $LG(window).scrollTop();
30991			setTimeout(function () {
30992				// Need to check both zoomFromOrigin and transform values as we need to set set the
30993				// default opening animation if user missed to add the lg-size attribute
30994				if (_this.zoomFromOrigin && transform) {
30995					var currentSlide_1 = _this.getSlideItem(index);
30996					currentSlide_1.css('transform', transform);
30997					setTimeout(function () {
30998						currentSlide_1
30999							.addClass('lg-start-progress lg-start-end-progress')
31000							.css('transition-duration', _this.settings.startAnimationDuration + 'ms');
31001						_this.outer.addClass('lg-zoom-from-image');
31002					});
31003					setTimeout(function () {
31004						currentSlide_1.css('transform', 'translate3d(0, 0, 0)');
31005					}, 100);
31006				}
31007				setTimeout(function () {
31008					_this.$backdrop.addClass('in');
31009					_this.$container.addClass('lg-show-in');
31010				}, 10);
31011				setTimeout(function () {
31012					if (_this.settings.trapFocus &&
31013						document.body === _this.settings.container) {
31014						_this.trapFocus();
31015					}
31016				}, _this.settings.backdropDuration + 50);
31017				// lg-visible class resets gallery opacity to 1
31018				if (!_this.zoomFromOrigin || !transform) {
31019					setTimeout(function () {
31020						_this.outer.addClass('lg-visible');
31021					}, _this.settings.backdropDuration);
31022				}
31023				// initiate slide function
31024				_this.slide(index, false, false, false);
31025				_this.LGel.trigger(lGEvents.afterOpen);
31026			});
31027			if (document.body === this.settings.container) {
31028				$LG('html').addClass('lg-on');
31029			}
31030		};
31031		/**
31032		 * Note - Changing the position of the media on every slide transition creates a flickering effect.
31033		 * Therefore, The height of the caption is calculated dynamically, only once based on the first slide caption.
31034		 * if you have dynamic captions for each media,
31035		 * you can provide an appropriate height for the captions via allowMediaOverlap option
31036		 */
31037		LightGallery.prototype.getMediaContainerPosition = function () {
31038			if (this.settings.allowMediaOverlap) {
31039				return {
31040					top: 0,
31041					bottom: 0,
31042				};
31043			}
31044			var top = this.$toolbar.get().clientHeight || 0;
31045			var subHtml = this.outer.find('.lg-components .lg-sub-html').get();
31046			var captionHeight = this.settings.defaultCaptionHeight ||
31047				(subHtml && subHtml.clientHeight) ||
31048				0;
31049			var thumbContainer = this.outer.find('.lg-thumb-outer').get();
31050			var thumbHeight = thumbContainer ? thumbContainer.clientHeight : 0;
31051			var bottom = thumbHeight + captionHeight;
31052			//Uncode edit ##START##
31053			bottom = bottom < 55 ? 55 : bottom;
31054			//Uncode edit ##END##
31055			return {
31056				top: top,
31057				bottom: bottom,
31058			};
31059		};
31060		LightGallery.prototype.setMediaContainerPosition = function (top, bottom) {
31061			if (top === void 0) { top = 0; }
31062			if (bottom === void 0) { bottom = 0; }
31063			this.$content.css('top', top + 'px').css('bottom', bottom + 'px');
31064		};
31065		LightGallery.prototype.hideBars = function () {
31066			var _this = this;
31067			// Hide controllers if mouse doesn't move for some period
31068			setTimeout(function () {
31069				_this.outer.removeClass('lg-hide-items');
31070				if (_this.settings.hideBarsDelay > 0) {
31071					_this.outer.on('mousemove.lg click.lg touchstart.lg', function () {
31072						_this.outer.removeClass('lg-hide-items');
31073						clearTimeout(_this.hideBarTimeout);
31074						// Timeout will be cleared on each slide movement also
31075						_this.hideBarTimeout = setTimeout(function () {
31076							_this.outer.addClass('lg-hide-items');
31077						}, _this.settings.hideBarsDelay);
31078					});
31079					_this.outer.trigger('mousemove.lg');
31080				}
31081			}, this.settings.showBarsAfter);
31082		};
31083		LightGallery.prototype.initPictureFill = function ($img) {
31084			if (this.settings.supportLegacyBrowser) {
31085				try {
31086					picturefill({
31087						elements: [$img.get()],
31088					});
31089				}
31090				catch (e) {
31091					console.warn('lightGallery :- If you want srcset or picture tag to be supported for older browser please include picturefil javascript library in your document.');
31092				}
31093			}
31094		};
31095		/**
31096		 *  @desc Create image counter
31097		 *  Ex: 1/10
31098		 */
31099		LightGallery.prototype.counter = function () {
31100			if (this.settings.counter) {
31101				var counterHtml = "<div class=\"lg-counter\" role=\"status\" aria-live=\"polite\">\n                <span id=\"" + this.getIdName('lg-counter-current') + "\" class=\"lg-counter-current\">" + (this.index + 1) + " </span> /\n                <span id=\"" + this.getIdName('lg-counter-all') + "\" class=\"lg-counter-all\">" + this.galleryItems.length + " </span></div>";
31102				this.outer.find(this.settings.appendCounterTo).append(counterHtml);
31103			}
31104		};
31105		/**
31106		 *  @desc add sub-html into the slide
31107		 *  @param {Number} index - index of the slide
31108		 */
31109		LightGallery.prototype.addHtml = function (index) {
31110			var subHtml;
31111			var subHtmlUrl;
31112			if (this.galleryItems[index].subHtmlUrl) {
31113				subHtmlUrl = this.galleryItems[index].subHtmlUrl;
31114			}
31115			else {
31116				subHtml = this.galleryItems[index].subHtml;
31117			}
31118			if (!subHtmlUrl) {
31119				if (subHtml) {
31120					// get first letter of sub-html
31121					// if first letter starts with . or # get the html form the jQuery object
31122					var fL = subHtml.substring(0, 1);
31123					if (fL === '.' || fL === '#') {
31124						if (this.settings.subHtmlSelectorRelative &&
31125							!this.settings.dynamic) {
31126							subHtml = $LG(this.items)
31127								.eq(index)
31128								.find(subHtml)
31129								.first()
31130								.html();
31131						}
31132						else {
31133							subHtml = $LG(subHtml).first().html();
31134						}
31135					}
31136				}
31137				else {
31138					subHtml = '';
31139				}
31140			}
31141			if (this.settings.appendSubHtmlTo !== '.lg-item') {
31142				if (subHtmlUrl) {
31143					this.outer.find('.lg-sub-html').load(subHtmlUrl);
31144				}
31145				else {
31146					this.outer.find('.lg-sub-html').html(subHtml);
31147				}
31148			}
31149			else {
31150				var currentSlide = $LG(this.getSlideItemId(index));
31151				if (subHtmlUrl) {
31152					currentSlide.load(subHtmlUrl);
31153				}
31154				else {
31155					currentSlide.append("<div class=\"lg-sub-html\">" + subHtml + "</div>");
31156				}
31157			}
31158			// Add lg-empty-html class if title doesn't exist
31159			if (typeof subHtml !== 'undefined' && subHtml !== null) {
31160				if (subHtml === '') {
31161					this.outer
31162						.find(this.settings.appendSubHtmlTo)
31163						.addClass('lg-empty-html');
31164				}
31165				else {
31166					this.outer
31167						.find(this.settings.appendSubHtmlTo)
31168						.removeClass('lg-empty-html');
31169				}
31170			}
31171			this.LGel.trigger(lGEvents.afterAppendSubHtml, {
31172				index: index,
31173			});
31174		};
31175		/**
31176		 *  @desc Preload slides
31177		 *  @param {Number} index - index of the slide
31178		 * @todo preload not working for the first slide, Also, should work for the first and last slide as well
31179		 */
31180		LightGallery.prototype.preload = function (index) {
31181			for (var i = 1; i <= this.settings.preload; i++) {
31182				if (i >= this.galleryItems.length - index) {
31183					break;
31184				}
31185				this.loadContent(index + i, false);
31186			}
31187			for (var j = 1; j <= this.settings.preload; j++) {
31188				if (index - j < 0) {
31189					break;
31190				}
31191				this.loadContent(index - j, false);
31192			}
31193		};
31194		LightGallery.prototype.getDummyImgStyles = function (imageSize) {
31195			if (!imageSize)
31196				return '';
31197			return "width:" + imageSize.width + "px;\n                margin-left: -" + imageSize.width / 2 + "px;\n                margin-top: -" + imageSize.height / 2 + "px;\n                height:" + imageSize.height + "px";
31198		};
31199		LightGallery.prototype.getVideoContStyle = function (imageSize) {
31200			if (!imageSize)
31201				return '';
31202			return "width:" + imageSize.width + "px;\n                height:" + imageSize.height + "px";
31203		};
31204		LightGallery.prototype.getDummyImageContent = function ($currentSlide, index, alt) {
31205			var $currentItem;
31206			if (!this.settings.dynamic) {
31207				$currentItem = $LG(this.items).eq(index);
31208			}
31209			if ($currentItem) {
31210				var _dummyImgSrc = void 0;
31211				if (!this.settings.exThumbImage) {
31212					_dummyImgSrc = $currentItem.find('img').first().attr('src');
31213				}
31214				else {
31215					_dummyImgSrc = $currentItem.attr(this.settings.exThumbImage);
31216				}
31217				if (!_dummyImgSrc)
31218					return '';
31219				var imgStyle = this.getDummyImgStyles(this.currentImageSize);
31220				var dummyImgContent = "<img " + alt + " style=\"" + imgStyle + "\" class=\"lg-dummy-img\" src=\"" + _dummyImgSrc + "\" />";
31221				$currentSlide.addClass('lg-first-slide');
31222				this.outer.addClass('lg-first-slide-loading');
31223				return dummyImgContent;
31224			}
31225			return '';
31226		};
31227		LightGallery.prototype.setImgMarkup = function (src, $currentSlide, index) {
31228			var currentGalleryItem = this.galleryItems[index];
31229			var alt = currentGalleryItem.alt, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources;
31230			// Use the thumbnail as dummy image which will be resized to actual image size and
31231			// displayed on top of actual image
31232			var imgContent = '';
31233			var altAttr = alt ? 'alt="' + alt + '"' : '';
31234			if (this.isFirstSlideWithZoomAnimation()) {
31235				imgContent = this.getDummyImageContent($currentSlide, index, altAttr);
31236			}
31237			else {
31238				imgContent = utils.getImgMarkup(index, src, altAttr, srcset, sizes, sources);
31239			}
31240			var imgMarkup = "<picture class=\"lg-img-wrap\"> " + imgContent + "</picture>";
31241			$currentSlide.prepend(imgMarkup);
31242		};
31243		LightGallery.prototype.onSlideObjectLoad = function ($slide, isHTML5VideoWithoutPoster, onLoad, onError) {
31244			var mediaObject = $slide.find('.lg-object').first();
31245			if (utils.isImageLoaded(mediaObject.get()) ||
31246				isHTML5VideoWithoutPoster) {
31247				onLoad();
31248			}
31249			else {
31250				mediaObject.on('load.lg error.lg', function () {
31251					onLoad && onLoad();
31252				});
31253				mediaObject.on('error.lg', function () {
31254					onError && onError();
31255				});
31256			}
31257		};
31258		/**
31259		 *
31260		 * @param $el Current slide item
31261		 * @param index
31262		 * @param delay Delay is 0 except first time
31263		 * @param speed Speed is same as delay, except it is 0 if gallery is opened via hash plugin
31264		 * @param isFirstSlide
31265		 */
31266		LightGallery.prototype.onLgObjectLoad = function (currentSlide, index, delay, speed, isFirstSlide, isHTML5VideoWithoutPoster) {
31267			var _this = this;
31268			//Uncode edit ##START##
31269			var $item = _this.galleryItems[index],
31270				type = $item.type;
31271
31272			if ( typeof $item.src !== 'undefined' ) {
31273				var inline_id = $item.src.replace('#', ''),
31274					$inline = document.getElementById(inline_id),
31275					inline_html;
31276
31277				if ( type === 'inline' && inline_id != null && typeof $inline !== 'undefined' ) {
31278					inline_html = $inline.innerHTML;
31279				} else {
31280					inline_html = '';
31281				}
31282			}
31283			//Uncode edit ##END##
31284			this.onSlideObjectLoad(currentSlide, true, function () {
31285				_this.triggerSlideItemLoad(currentSlide, index, delay, speed, isFirstSlide);
31286			}, function () {
31287				currentSlide.addClass('lg-complete lg-complete_');
31288				//Uncode edit ##START##
31289				// currentSlide.html('<span class="lg-error-msg">Oops... Failed to load content...</span>');
31290				if ( inline_html !== '' ) {
31291					currentSlide.html(inline_html);
31292				} else {
31293					currentSlide.html('<span class="lg-error-msg">Oops... Failed to load content...</span>');
31294				}
31295				//Uncode edit ##END##
31296			});
31297		};
31298		LightGallery.prototype.triggerSlideItemLoad = function ($currentSlide, index, delay, speed, isFirstSlide) {
31299			var _this = this;
31300			var currentGalleryItem = this.galleryItems[index];
31301			// Adding delay for video slides without poster for better performance and user experience
31302			// Videos should start playing once once the gallery is completely loaded
31303			var _speed = isFirstSlide &&
vendor: 3,676 bytes, lines 31304-31392
31304				this.getSlideType(currentGalleryItem) === 'video' &&
31305				!currentGalleryItem.poster
31306				? speed
31307				: 0;
31308			setTimeout(function () {
31309				$currentSlide.addClass('lg-complete lg-complete_');
31310				_this.LGel.trigger(lGEvents.slideItemLoad, {
31311					index: index,
31312					delay: delay || 0,
31313					isFirstSlide: isFirstSlide,
31314				});
31315			}, _speed);
31316		};
31317		LightGallery.prototype.isFirstSlideWithZoomAnimation = function () {
31318			return !!(!this.lGalleryOn &&
31319				this.zoomFromOrigin &&
31320				this.currentImageSize);
31321		};
31322		// Add video slideInfo
31323		LightGallery.prototype.addSlideVideoInfo = function (items) {
31324			var _this = this;
31325			items.forEach(function (element, index) {
31326				element.__slideVideoInfo = utils.isVideo(element.src, !!element.video, index);
31327				if (element.__slideVideoInfo &&
31328					_this.settings.loadYouTubePoster &&
31329					!element.poster &&
31330					element.__slideVideoInfo.youtube) {
31331					element.poster = "//img.youtube.com/vi/" + element.__slideVideoInfo.youtube[1] + "/maxresdefault.jpg";
31332				}
31333			});
31334		};
31335		/**
31336		 *  Load slide content into slide.
31337		 *  This is used to load content into slides that is not visible too
31338		 *  @param {Number} index - index of the slide.
31339		 *  @param {Boolean} rec - if true call loadcontent() function again.
31340		 */
31341		LightGallery.prototype.loadContent = function (index, rec) {
31342			var _this = this;
31343			var currentGalleryItem = this.galleryItems[index];
31344			var $currentSlide = $LG(this.getSlideItemId(index));
31345			var poster = currentGalleryItem.poster, srcset = currentGalleryItem.srcset, sizes = currentGalleryItem.sizes, sources = currentGalleryItem.sources;
31346			var src = currentGalleryItem.src;
31347			var video = currentGalleryItem.video;
31348			var _html5Video = video && typeof video === 'string' ? JSON.parse(video) : video;
31349			if (currentGalleryItem.responsive) {
31350				var srcDyItms = currentGalleryItem.responsive.split(',');
31351				src = utils.getResponsiveSrc(srcDyItms) || src;
31352			}
31353			var videoInfo = currentGalleryItem.__slideVideoInfo;
31354			var lgVideoStyle = '';
31355			var iframe = !!currentGalleryItem.iframe;
31356			var isFirstSlide = !this.lGalleryOn;
31357			// delay for adding complete class. it is 0 except first time.
31358			var delay = 0;
31359			if (isFirstSlide) {
31360				if (this.zoomFromOrigin && this.currentImageSize) {
31361					delay = this.settings.startAnimationDuration + 10;
31362				}
31363				else {
31364					delay = this.settings.backdropDuration + 10;
31365				}
31366			}
31367			if (!$currentSlide.hasClass('lg-loaded')) {
31368				if (videoInfo) {
31369					var _a = this.mediaContainerPosition, top_2 = _a.top, bottom = _a.bottom;
31370					//Uncode edit ##START##
31371					var videoSize = utils.getSize(this.items[index], this.outer, top_2 + bottom, videoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]);
31372					// var videoSize = utils.getSize(this.items[index], this.outer, top_2 + bottom, videoInfo && this.settings.videoMaxSize);
31373					//Uncode edit ##END##
31374					lgVideoStyle = this.getVideoContStyle(videoSize);
31375				}
31376				if (iframe) {
31377					var markup = utils.getIframeMarkup(this.settings.iframeWidth, this.settings.iframeHeight, this.settings.iframeMaxWidth, this.settings.iframeMaxHeight, src, currentGalleryItem.iframeTitle);
31378					$currentSlide.prepend(markup);
31379				}
31380				else if (poster) {
31381					var dummyImg = '';
31382					var hasStartAnimation = isFirstSlide &&
31383						this.zoomFromOrigin &&
31384						this.currentImageSize;
31385					if (hasStartAnimation) {
31386						dummyImg = this.getDummyImageContent($currentSlide, index, '');
31387					}
31388					var markup = utils.getVideoPosterMarkup(poster, dummyImg || '', lgVideoStyle, this.settings.strings['playVideo'], videoInfo);
31389					$currentSlide.prepend(markup);
31390				}
31391				//Uncode edit ##START##
31392				// else if (videoInfo) {
31393				else if (videoInfo || this.getSlideType(currentGalleryItem) === 'audio') {
31394					if (! _html5Video) {
31395						var markup = "<div class=\"lg-video-cont \" style=\"" + lgVideoStyle + "\"></div>";
31396					}
31397					//Uncode edit ##END##
31398					$currentSlide.prepend(markup);
31399				}
31400				else {
31401					//Uncode edit ##START##
31402					var $item = _this.galleryItems[index],
31403						type = $item.type;
31404
31405					if ( typeof $item.src !== 'undefined' ) {
31406						var inline_id = $item.src.replace('#', ''),
31407							$inline = document.getElementById(inline_id),
31408							inline_html;
31409
31410						if ( type === 'inline' && inline_id != null && typeof $inline !== 'undefined' ) {
31411							inline_html = $inline.innerHTML;
31412						} else {
31413							inline_html = '';
31414						}
31415					}
31416					if ( inline_html !== '' ) {
31417						$currentSlide.html(inline_html);
31418					} else {
31419						this.setImgMarkup(src, $currentSlide, index);
31420						if (srcset || sources) {
31421							var $img = $currentSlide.find('.lg-object');
31422							this.initPictureFill($img);
31423						}
31424					}
31425					/*this.setImgMarkup(src, $currentSlide, index);
31426					if (srcset || sources) {
31427						var $img = $currentSlide.find('.lg-object');
31428						this.initPictureFill($img);
31429					}*/
31430					//Uncode edit ##END##
31431				}
31432				if (poster || videoInfo) {
31433					this.LGel.trigger(lGEvents.hasVideo, {
31434						index: index,
31435						src: src,
31436						html5Video: _html5Video,
31437						hasPoster: !!poster,
31438					});
31439				}
31440				this.LGel.trigger(lGEvents.afterAppendSlide, { index: index });
31441				if (this.lGalleryOn &&
31442					this.settings.appendSubHtmlTo === '.lg-item') {
31443					this.addHtml(index);
31444				}
31445			}
31446			// For first time add some delay for displaying the start animation.
31447			var _speed = 0;
31448			// Do not change the delay value because it is required for zoom plugin.
31449			// If gallery opened from direct url (hash) speed value should be 0
31450			if (delay && !$LG(document.body).hasClass('lg-from-hash')) {
31451				_speed = delay;
31452			}
31453			// Only for first slide and zoomFromOrigin is enabled
31454			if (this.isFirstSlideWithZoomAnimation()) {
31455				setTimeout(function () {
31456					$currentSlide
31457						.removeClass('lg-start-end-progress lg-start-progress')
31458						.removeAttr('style');
31459				}, this.settings.startAnimationDuration + 100);
31460				if (!$currentSlide.hasClass('lg-loaded')) {
31461					setTimeout(function () {
31462						if (_this.getSlideType(currentGalleryItem) === 'image') {
31463							var alt = currentGalleryItem.alt;
31464							var altAttr = alt ? 'alt="' + alt + '"' : '';
31465							$currentSlide
31466								.find('.lg-img-wrap')
31467								.append(utils.getImgMarkup(index, src, altAttr, srcset, sizes, currentGalleryItem.sources));
31468							if (srcset || sources) {
31469								var $img = $currentSlide.find('.lg-object');
31470								_this.initPictureFill($img);
31471							}
31472						}
31473						if (_this.getSlideType(currentGalleryItem) === 'image' ||
31474							(_this.getSlideType(currentGalleryItem) === 'video' &&
31475								poster)) {
31476							_this.onLgObjectLoad($currentSlide, index, delay, _speed, true, false);
31477							// load remaining slides once the slide is completely loaded
31478							_this.onSlideObjectLoad($currentSlide, !!(videoInfo && videoInfo.html5 && !poster), function () {
31479								_this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed);
31480							}, function () {
31481								_this.loadContentOnFirstSlideLoad(index, $currentSlide, _speed);
31482							});
31483						}
31484					}, this.settings.startAnimationDuration + 100);
31485				}
31486			}
31487			// SLide content has been added to dom
31488			$currentSlide.addClass('lg-loaded');
31489			if (!this.isFirstSlideWithZoomAnimation() ||
31490				(this.getSlideType(currentGalleryItem) === 'video' && !poster)) {
31491				//Uncode edit ##START##
31492				// this.onLgObjectLoad($currentSlide, index, delay, _speed, isFirstSlide, !!(videoInfo && videoInfo.html5 && !poster));
31493				this.onLgObjectLoad($currentSlide, index, delay, _speed, isFirstSlide, !!( (videoInfo && videoInfo.html5 && !poster) || this.get
vendor: 31,133 bytes, lines 31493-32417
31493SlideType(currentGalleryItem) === 'audio'));
31494				//Uncode edit ##END##
31495			}
31496			// When gallery is opened once content is loaded (second time) need to add lg-complete class for css styling
31497			if ((!this.zoomFromOrigin || !this.currentImageSize) &&
31498				$currentSlide.hasClass('lg-complete_') &&
31499				!this.lGalleryOn) {
31500				setTimeout(function () {
31501					$currentSlide.addClass('lg-complete');
31502				}, this.settings.backdropDuration);
31503			}
31504			// Content loaded
31505			// Need to set lGalleryOn before calling preload function
31506			this.lGalleryOn = true;
31507			if (rec === true) {
31508				if (!$currentSlide.hasClass('lg-complete_')) {
31509					$currentSlide
31510						.find('.lg-object')
31511						.first()
31512						.on('load.lg error.lg', function () {
31513						_this.preload(index);
31514					});
31515				}
31516				else {
31517					this.preload(index);
31518				}
31519			}
31520		};
31521		/**
31522		 * @desc Remove dummy image content and load next slides
31523		 * Called only for the first time if zoomFromOrigin animation is enabled
31524		 * @param index
31525		 * @param $currentSlide
31526		 * @param speed
31527		 */
31528		LightGallery.prototype.loadContentOnFirstSlideLoad = function (index, $currentSlide, speed) {
31529			var _this = this;
31530			setTimeout(function () {
31531				$currentSlide.find('.lg-dummy-img').remove();
31532				$currentSlide.removeClass('lg-first-slide');
31533				_this.outer.removeClass('lg-first-slide-loading');
31534				_this.isDummyImageRemoved = true;
31535				_this.preload(index);
31536			}, speed + 300);
31537		};
31538		LightGallery.prototype.getItemsToBeInsertedToDom = function (index, prevIndex, numberOfItems) {
31539			var _this = this;
31540			if (numberOfItems === void 0) { numberOfItems = 0; }
31541			var itemsToBeInsertedToDom = [];
31542			// Minimum 2 items should be there
31543			var possibleNumberOfItems = Math.max(numberOfItems, 3);
31544			possibleNumberOfItems = Math.min(possibleNumberOfItems, this.galleryItems.length);
31545			var prevIndexItem = "lg-item-" + this.lgId + "-" + prevIndex;
31546			if (this.galleryItems.length <= 3) {
31547				this.galleryItems.forEach(function (_element, index) {
31548					itemsToBeInsertedToDom.push("lg-item-" + _this.lgId + "-" + index);
31549				});
31550				return itemsToBeInsertedToDom;
31551			}
31552			if (index < (this.galleryItems.length - 1) / 2) {
31553				for (var idx = index; idx > index - possibleNumberOfItems / 2 && idx >= 0; idx--) {
31554					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx);
31555				}
31556				var numberOfExistingItems = itemsToBeInsertedToDom.length;
31557				for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) {
31558					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index + idx + 1));
31559				}
31560			}
31561			else {
31562				for (var idx = index; idx <= this.galleryItems.length - 1 &&
31563					idx < index + possibleNumberOfItems / 2; idx++) {
31564					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + idx);
31565				}
31566				var numberOfExistingItems = itemsToBeInsertedToDom.length;
31567				for (var idx = 0; idx < possibleNumberOfItems - numberOfExistingItems; idx++) {
31568					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (index - idx - 1));
31569				}
31570			}
31571			if (this.settings.loop) {
31572				if (index === this.galleryItems.length - 1) {
31573					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + 0);
31574				}
31575				else if (index === 0) {
31576					itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + (this.galleryItems.length - 1));
31577				}
31578			}
31579			if (itemsToBeInsertedToDom.indexOf(prevIndexItem) === -1) {
31580				itemsToBeInsertedToDom.push("lg-item-" + this.lgId + "-" + prevIndex);
31581			}
31582			return itemsToBeInsertedToDom;
31583		};
31584		LightGallery.prototype.organizeSlideItems = function (index, prevIndex) {
31585			var _this = this;
31586			var itemsToBeInsertedToDom = this.getItemsToBeInsertedToDom(index, prevIndex, this.settings.numberOfSlideItemsInDom);
31587			itemsToBeInsertedToDom.forEach(function (item) {
31588				if (_this.currentItemsInDom.indexOf(item) === -1) {
31589					_this.$inner.append("<div id=\"" + item + "\" class=\"lg-item\"></div>");
31590				}
31591			});
31592			this.currentItemsInDom.forEach(function (item) {
31593				if (itemsToBeInsertedToDom.indexOf(item) === -1) {
31594					$LG("#" + item).remove();
31595				}
31596			});
31597			return itemsToBeInsertedToDom;
31598		};
31599		/**
31600		 * Get previous index of the slide
31601		 */
31602		LightGallery.prototype.getPreviousSlideIndex = function () {
31603			var prevIndex = 0;
31604			try {
31605				var currentItemId = this.outer
31606					.find('.lg-current')
31607					.first()
31608					.attr('id');
31609				prevIndex = parseInt(currentItemId.split('-')[3]) || 0;
31610			}
31611			catch (error) {
31612				prevIndex = 0;
31613			}
31614			return prevIndex;
31615		};
31616		LightGallery.prototype.setDownloadValue = function (index) {
31617			if (this.settings.download) {
31618				var currentGalleryItem = this.galleryItems[index];
31619				var hideDownloadBtn = currentGalleryItem.downloadUrl === false ||
31620					currentGalleryItem.downloadUrl === 'false';
31621				if (hideDownloadBtn) {
31622					this.outer.addClass('lg-hide-download');
31623				}
31624				else {
31625					var $download = this.getElementById('lg-download');
31626					this.outer.removeClass('lg-hide-download');
31627					$download.attr('href', currentGalleryItem.downloadUrl ||
31628						currentGalleryItem.src);
31629					if (currentGalleryItem.download) {
31630						//Uncode edit ##START##
31631						if ( typeof currentGalleryItem.video !== 'undefined' && currentGalleryItem.video ) {
31632							var currentVideo = JSON.parse( currentGalleryItem.video ),
31633								download_name = currentVideo.source[0].src;
31634							$download.attr('href', download_name).removeAttr('download');
31635						} else {
31636							var download_url = currentGalleryItem.downloadUrl || currentGalleryItem.src,
31637								download_name = download_url.substring(download_url.lastIndexOf('/')+1);
31638							$download.attr('download', download_name);
31639						}
31640						// $download.attr('download', currentGalleryItem.download);
31641						//Uncode edit ##END##
31642					}
31643				}
31644			}
31645		};
31646		LightGallery.prototype.makeSlideAnimation = function (direction, currentSlideItem, previousSlideItem) {
31647			var _this = this;
31648			if (this.lGalleryOn) {
31649				previousSlideItem.addClass('lg-slide-progress');
31650			}
31651			setTimeout(function () {
31652				// remove all transitions
31653				_this.outer.addClass('lg-no-trans');
31654				_this.outer
31655					.find('.lg-item')
31656					.removeClass('lg-prev-slide lg-next-slide');
31657				if (direction === 'prev') {
31658					//prevslide
31659					currentSlideItem.addClass('lg-prev-slide');
31660					previousSlideItem.addClass('lg-next-slide');
31661				}
31662				else {
31663					// next slide
31664					currentSlideItem.addClass('lg-next-slide');
31665					previousSlideItem.addClass('lg-prev-slide');
31666				}
31667				// give 50 ms for browser to add/remove class
31668				setTimeout(function () {
31669					_this.outer.find('.lg-item').removeClass('lg-current');
31670					currentSlideItem.addClass('lg-current');
31671					// reset all transitions
31672					_this.outer.removeClass('lg-no-trans');
31673				}, 50);
31674			}, this.lGalleryOn ? this.settings.slideDelay : 0);
31675		};
31676		/**
31677		 * Goto a specific slide.
31678		 * @param {Number} index - index of the slide
31679		 * @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag
31680		 * @param {Boolean} fromThumb - true if slide function called via thumbnail click
31681		 * @param {String} direction - Direction of the slide(next/prev)
31682		 * @category lGPublicMethods
31683		 * @example
31684		 *  const plugin = lightGallery();
31685		 *  // to go to 3rd slide
31686		 *  plugin.slide(2);
31687		 *
31688		 */
31689		LightGallery.prototype.slide = function (index, fromTouch, fromThumb, direction) {
31690			var _this = this;
31691			var prevIndex = this.getPreviousSlideIndex();
31692			this.currentItemsInDom = this.organizeSlideItems(index, prevIndex);
31693			// Prevent multiple call, Required for hsh plugin
31694			if (this.lGalleryOn && prevIndex === index) {
31695				return;
31696			}
31697			var numberOfGalleryItems = this.galleryItems.length;
31698			if (!this.lgBusy) {
31699				if (this.settings.counter) {
31700					this.updateCurrentCounter(index);
31701				}
31702				var currentSlideItem = this.getSlideItem(index);
31703				var previousSlideItem_1 = this.getSlideItem(prevIndex);
31704				var currentGalleryItem = this.galleryItems[index];
31705				var videoInfo = currentGalleryItem.__slideVideoInfo;
31706				this.outer.attr('data-lg-slide-type', this.getSlideType(currentGalleryItem));
31707				this.setDownloadValue(index);
31708				if (videoInfo) {
31709					var _a = this.mediaContainerPosition, top_3 = _a.top, bottom = _a.bottom;
31710					//Uncode edit ##START##
31711					var videoSize = utils.getSize(this.items[index], this.outer, top_3 + bottom, videoInfo && this.settings.videoMaxSize, this.galleryItems[this.index]);
31712					// var videoSize = utils.getSize(this.items[index], this.outer, top_3 + bottom, videoInfo && this.settings.videoMaxSize);
31713					//Uncode edit ##END##
31714					this.resizeVideoSlide(index, videoSize);
31715				}
31716				this.LGel.trigger(lGEvents.beforeSlide, {
31717					prevIndex: prevIndex,
31718					index: index,
31719					fromTouch: !!fromTouch,
31720					fromThumb: !!fromThumb,
31721					//Uncode edit ##START##
31722					currentSlide: currentSlideItem,
31723					previousSlide: previousSlideItem_1,
31724					info: currentGalleryItem,
31725					item: this.items[index]
31726					//Uncode edit ##END##
31727				});
31728				this.lgBusy = true;
31729				clearTimeout(this.hideBarTimeout);
31730				this.arrowDisable(index);
31731				if (!direction) {
31732					if (index < prevIndex) {
31733						direction = 'prev';
31734					}
31735					else if (index > prevIndex) {
31736						direction = 'next';
31737					}
31738				}
31739				if (!fromTouch) {
31740					this.makeSlideAnimation(direction, currentSlideItem, previousSlideItem_1);
31741				}
31742				else {
31743					this.outer
31744						.find('.lg-item')
31745						.removeClass('lg-prev-slide lg-current lg-next-slide');
31746					var touchPrev = void 0;
31747					var touchNext = void 0;
31748					if (numberOfGalleryItems > 2) {
31749						touchPrev = index - 1;
31750						touchNext = index + 1;
31751						if (index === 0 && prevIndex === numberOfGalleryItems - 1) {
31752							// next slide
31753							touchNext = 0;
31754							touchPrev = numberOfGalleryItems - 1;
31755						}
31756						else if (index === numberOfGalleryItems - 1 &&
31757							prevIndex === 0) {
31758							// prev slide
31759							touchNext = 0;
31760							touchPrev = numberOfGalleryItems - 1;
31761						}
31762					}
31763					else {
31764						touchPrev = 0;
31765						touchNext = 1;
31766					}
31767					if (direction === 'prev') {
31768						this.getSlideItem(touchNext).addClass('lg-next-slide');
31769					}
31770					else {
31771						this.getSlideItem(touchPrev).addClass('lg-prev-slide');
31772					}
31773					currentSlideItem.addClass('lg-current');
31774				}
31775				// Do not put load content in set timeout as it needs to load immediately when the gallery is opened
31776				if (!this.lGalleryOn) {
31777					this.loadContent(index, true);
31778				}
31779				else {
31780					setTimeout(function () {
31781						_this.loadContent(index, true);
31782						// Add title if this.settings.appendSubHtmlTo === lg-sub-html
31783						if (_this.settings.appendSubHtmlTo !== '.lg-item') {
31784							_this.addHtml(index);
31785						}
31786					}, this.settings.speed + 50 + (fromTouch ? 0 : this.settings.slideDelay));
31787				}
31788				setTimeout(function () {
31789					_this.lgBusy = false;
31790					previousSlideItem_1.removeClass('lg-slide-progress');
31791					_this.LGel.trigger(lGEvents.afterSlide, {
31792						prevIndex: prevIndex,
31793						index: index,
31794						fromTouch: fromTouch,
31795						fromThumb: fromThumb,
31796					});
31797				}, (this.lGalleryOn ? this.settings.speed + 100 : 100) + (fromTouch ? 0 : this.settings.slideDelay));
31798			}
31799			this.index = index;
31800		};
31801		LightGallery.prototype.updateCurrentCounter = function (index) {
31802			this.getElementById('lg-counter-current').html(index + 1 + '');
31803		};
31804		LightGallery.prototype.updateCounterTotal = function () {
31805			this.getElementById('lg-counter-all').html(this.galleryItems.length + '');
31806		};
31807		LightGallery.prototype.getSlideType = function (item) {
31808			if (item.__slideVideoInfo) {
31809				return 'video';
31810			}
31811			else if (item.iframe) {
31812				return 'iframe';
31813			}
31814			//Uncode edit ##START##
31815			else if (typeof item.src !== '' && item.src.search(/.mp3|.m4a/i) > -1) {
31816				return 'audio';
31817			}
31818			//Uncode edit ##END##
31819			else {
31820				return 'image';
31821			}
31822		};
31823		LightGallery.prototype.touchMove = function (startCoords, endCoords, e) {
31824			var distanceX = endCoords.pageX - startCoords.pageX;
31825			var distanceY = endCoords.pageY - startCoords.pageY;
31826			var allowSwipe = false;
31827			if (this.swipeDirection) {
31828				allowSwipe = true;
31829			}
31830			else {
31831				if (Math.abs(distanceX) > 15) {
31832					this.swipeDirection = 'horizontal';
31833					allowSwipe = true;
31834				}
31835				else if (Math.abs(distanceY) > 15) {
31836					this.swipeDirection = 'vertical';
31837					allowSwipe = true;
31838				}
31839			}
31840			if (!allowSwipe) {
31841				return;
31842			}
31843			var $currentSlide = this.getSlideItem(this.index);
31844			if (this.swipeDirection === 'horizontal') {
31845				e === null || e === void 0 ? void 0 : e.preventDefault();
31846				// reset opacity and transition duration
31847				this.outer.addClass('lg-dragging');
31848				// move current slide
31849				this.setTranslate($currentSlide, distanceX, 0);
31850				// move next and prev slide with current slide
31851				var width = $currentSlide.get().offsetWidth;
31852				var slideWidthAmount = (width * 15) / 100;
31853				var gutter = slideWidthAmount - Math.abs((distanceX * 10) / 100);
31854				this.setTranslate(this.outer.find('.lg-prev-slide').first(), -width + distanceX - gutter, 0);
31855				this.setTranslate(this.outer.find('.lg-next-slide').first(), width + distanceX + gutter, 0);
31856			}
31857			else if (this.swipeDirection === 'vertical') {
31858				if (this.settings.swipeToClose) {
31859					e === null || e === void 0 ? void 0 : e.preventDefault();
31860					this.$container.addClass('lg-dragging-vertical');
31861					var opacity = 1 - Math.abs(distanceY) / window.innerHeight;
31862					this.$backdrop.css('opacity', opacity);
31863					var scale = 1 - Math.abs(distanceY) / (window.innerWidth * 2);
31864					this.setTranslate($currentSlide, 0, distanceY, scale, scale);
31865					if (Math.abs(distanceY) > 100) {
31866						this.outer
31867							.addClass('lg-hide-items')
31868							.removeClass('lg-components-open');
31869					}
31870				}
31871			}
31872		};
31873		LightGallery.prototype.touchEnd = function (endCoords, startCoords, event) {
31874			var _this = this;
31875			var distance;
31876			// keep slide animation for any mode while dragg/swipe
31877			if (this.settings.mode !== 'lg-slide') {
31878				this.outer.addClass('lg-slide');
31879			}
31880			// set transition duration
31881			setTimeout(function () {
31882				_this.$container.removeClass('lg-dragging-vertical');
31883				_this.outer
31884					.removeClass('lg-dragging lg-hide-items')
31885					.addClass('lg-components-open');
31886				var triggerClick = true;
31887				if (_this.swipeDirection === 'horizontal') {
31888					distance = endCoords.pageX - startCoords.pageX;
31889					var distanceAbs = Math.abs(endCoords.pageX - startCoords.pageX);
31890					if (distance < 0 &&
31891						distanceAbs > _this.settings.swipeThreshold) {
31892						_this.goToNextSlide(true);
31893						triggerClick = false;
31894					}
31895					else if (distance > 0 &&
31896						distanceAbs > _this.settings.swipeThreshold) {
31897						_this.goToPrevSlide(true);
31898						triggerClick = false;
31899					}
31900				}
31901				else if (_this.swipeDirection === 'vertical') {
31902					distance = Math.abs(endCoords.pageY - startCoords.pageY);
31903					if (_this.settings.closable &&
31904						_this.settings.swipeToClose &&
31905						distance > 100) {
31906						_this.closeGallery();
31907						return;
31908					}
31909					else {
31910						_this.$backdrop.css('opacity', 1);
31911					}
31912				}
31913				_this.outer.find('.lg-item').removeAttr('style');
31914				if (triggerClick &&
31915					Math.abs(endCoords.pageX - startCoords.pageX) < 5) {
31916					// Trigger click if distance is less than 5 pix
31917					var target = $LG(event.target);
31918					if (_this.isPosterElement(target)) {
31919						_this.LGel.trigger(lGEvents.posterClick);
31920					}
31921				}
31922				_this.swipeDirection = undefined;
31923			});
31924			// remove slide class once drag/swipe is completed if mode is not slide
31925			setTimeout(function () {
31926				if (!_this.outer.hasClass('lg-dragging') &&
31927					_this.settings.mode !== 'lg-slide') {
31928					_this.outer.removeClass('lg-slide');
31929				}
31930			}, this.settings.speed + 100);
31931		};
31932		LightGallery.prototype.enableSwipe = function () {
31933			var _this = this;
31934			var startCoords = {};
31935			var endCoords = {};
31936			var isMoved = false;
31937			var isSwiping = false;
31938			if (this.settings.enableSwipe) {
31939				this.$inner.on('touchstart.lg', function (e) {
31940					_this.dragOrSwipeEnabled = true;
31941					var $item = _this.getSlideItem(_this.index);
31942					if (($LG(e.target).hasClass('lg-item') ||
31943						$item.get().contains(e.target)) &&
31944						!_this.outer.hasClass('lg-zoomed') &&
31945						!_this.lgBusy &&
31946						e.targetTouches.length === 1) {
31947						isSwiping = true;
31948						_this.touchAction = 'swipe';
31949						_this.manageSwipeClass();
31950						startCoords = {
31951							pageX: e.targetTouches[0].pageX,
31952							pageY: e.targetTouches[0].pageY,
31953						};
31954					}
31955				});
31956				this.$inner.on('touchmove.lg', function (e) {
31957					if (isSwiping &&
31958						_this.touchAction === 'swipe' &&
31959						e.targetTouches.length === 1) {
31960						endCoords = {
31961							pageX: e.targetTouches[0].pageX,
31962							pageY: e.targetTouches[0].pageY,
31963						};
31964						_this.touchMove(startCoords, endCoords, e);
31965						isMoved = true;
31966					}
31967				});
31968				this.$inner.on('touchend.lg', function (event) {
31969					if (_this.touchAction === 'swipe') {
31970						if (isMoved) {
31971							isMoved = false;
31972							_this.touchEnd(endCoords, startCoords, event);
31973						}
31974						else if (isSwiping) {
31975							var target = $LG(event.target);
31976							if (_this.isPosterElement(target)) {
31977								_this.LGel.trigger(lGEvents.posterClick);
31978							}
31979						}
31980						_this.touchAction = undefined;
31981						isSwiping = false;
31982					}
31983				});
31984			}
31985		};
31986		LightGallery.prototype.enableDrag = function () {
31987			var _this = this;
31988			var startCoords = {};
31989			var endCoords = {};
31990			var isDraging = false;
31991			var isMoved = false;
31992			if (this.settings.enableDrag) {
31993				this.outer.on('mousedown.lg', function (e) {
31994					_this.dragOrSwipeEnabled = true;
31995					var $item = _this.getSlideItem(_this.index);
31996					if ($LG(e.target).hasClass('lg-item') ||
31997						$item.get().contains(e.target)) {
31998						if (!_this.outer.hasClass('lg-zoomed') && !_this.lgBusy) {
31999							e.preventDefault();
32000							if (!_this.lgBusy) {
32001								_this.manageSwipeClass();
32002								startCoords = {
32003									pageX: e.pageX,
32004									pageY: e.pageY,
32005								};
32006								isDraging = true;
32007								// ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
32008								_this.outer.get().scrollLeft += 1;
32009								_this.outer.get().scrollLeft -= 1;
32010								// *
32011								_this.outer
32012									.removeClass('lg-grab')
32013									.addClass('lg-grabbing');
32014								_this.LGel.trigger(lGEvents.dragStart);
32015							}
32016						}
32017					}
32018				});
32019				$LG(window).on("mousemove.lg.global" + this.lgId, function (e) {
32020					if (isDraging && _this.lgOpened) {
32021						isMoved = true;
32022						endCoords = {
32023							pageX: e.pageX,
32024							pageY: e.pageY,
32025						};
32026						_this.touchMove(startCoords, endCoords);
32027						_this.LGel.trigger(lGEvents.dragMove);
32028					}
32029				});
32030				$LG(window).on("mouseup.lg.global" + this.lgId, function (event) {
32031					if (!_this.lgOpened) {
32032						return;
32033					}
32034					var target = $LG(event.target);
32035					if (isMoved) {
32036						isMoved = false;
32037						_this.touchEnd(endCoords, startCoords, event);
32038						_this.LGel.trigger(lGEvents.dragEnd);
32039					}
32040					else if (_this.isPosterElement(target)) {
32041						_this.LGel.trigger(lGEvents.posterClick);
32042					}
32043					// Prevent execution on click
32044					if (isDraging) {
32045						isDraging = false;
32046						_this.outer.removeClass('lg-grabbing').addClass('lg-grab');
32047					}
32048				});
32049			}
32050		};
32051		LightGallery.prototype.triggerPosterClick = function () {
32052			var _this = this;
32053			this.$inner.on('click.lg', function (event) {
32054				if (!_this.dragOrSwipeEnabled &&
32055					_this.isPosterElement($LG(event.target))) {
32056					_this.LGel.trigger(lGEvents.posterClick);
32057				}
32058			});
32059		};
32060		LightGallery.prototype.manageSwipeClass = function () {
32061			var _touchNext = this.index + 1;
32062			var _touchPrev = this.index - 1;
32063			if (this.settings.loop && this.galleryItems.length > 2) {
32064				if (this.index === 0) {
32065					_touchPrev = this.galleryItems.length - 1;
32066				}
32067				else if (this.index === this.galleryItems.length - 1) {
32068					_touchNext = 0;
32069				}
32070			}
32071			this.outer.find('.lg-item').removeClass('lg-next-slide lg-prev-slide');
32072			if (_touchPrev > -1) {
32073				this.getSlideItem(_touchPrev).addClass('lg-prev-slide');
32074			}
32075			this.getSlideItem(_touchNext).addClass('lg-next-slide');
32076		};
32077		/**
32078		 * Go to next slide
32079		 * @param {Boolean} fromTouch - true if slide function called via touch event
32080		 * @category lGPublicMethods
32081		 * @example
32082		 *  const plugin = lightGallery();
32083		 *  plugin.goToNextSlide();
32084		 * @see <a href="/demos/methods/">Demo</a>
32085		 */
32086		LightGallery.prototype.goToNextSlide = function (fromTouch) {
32087			var _this = this;
32088			var _loop = this.settings.loop;
32089			if (fromTouch && this.galleryItems.length < 3) {
32090				_loop = false;
32091			}
32092			if (!this.lgBusy) {
32093				if (this.index + 1 < this.galleryItems.length) {
32094					this.index++;
32095					this.LGel.trigger(lGEvents.beforeNextSlide, {
32096						index: this.index,
32097					});
32098					this.slide(this.index, !!fromTouch, false, 'next');
32099				}
32100				else {
32101					if (_loop) {
32102						this.index = 0;
32103						this.LGel.trigger(lGEvents.beforeNextSlide, {
32104							index: this.index,
32105						});
32106						this.slide(this.index, !!fromTouch, false, 'next');
32107					}
32108					else if (this.settings.slideEndAnimation && !fromTouch) {
32109						this.outer.addClass('lg-right-end');
32110						setTimeout(function () {
32111							_this.outer.removeClass('lg-right-end');
32112						}, 400);
32113					}
32114				}
32115			}
32116		};
32117		/**
32118		 * Go to previous slides
32119		 * @param {Boolean} fromTouch - true if slide function called via touch event
32120		 * @category lGPublicMethods
32121		 * @example
32122		 *  const plugin = lightGallery({});
32123		 *  plugin.goToPrevSlide();
32124		 * @see <a href="/demos/methods/">Demo</a>
32125		 *
32126		 */
32127		LightGallery.prototype.goToPrevSlide = function (fromTouch) {
32128			var _this = this;
32129			var _loop = this.settings.loop;
32130			if (fromTouch && this.galleryItems.length < 3) {
32131				_loop = false;
32132			}
32133			if (!this.lgBusy) {
32134				if (this.index > 0) {
32135					this.index--;
32136					this.LGel.trigger(lGEvents.beforePrevSlide, {
32137						index: this.index,
32138						fromTouch: fromTouch,
32139					});
32140					this.slide(this.index, !!fromTouch, false, 'prev');
32141				}
32142				else {
32143					if (_loop) {
32144						this.index = this.galleryItems.length - 1;
32145						this.LGel.trigger(lGEvents.beforePrevSlide, {
32146							index: this.index,
32147							fromTouch: fromTouch,
32148						});
32149						this.slide(this.index, !!fromTouch, false, 'prev');
32150					}
32151					else if (this.settings.slideEndAnimation && !fromTouch) {
32152						this.outer.addClass('lg-left-end');
32153						setTimeout(function () {
32154							_this.outer.removeClass('lg-left-end');
32155						}, 400);
32156					}
32157				}
32158			}
32159		};
32160		LightGallery.prototype.keyPress = function () {
32161			var _this = this;
32162			$LG(window).on("keydown.lg.global" + this.lgId, function (e) {
32163				if (_this.lgOpened &&
32164					_this.settings.escKey === true &&
32165					e.keyCode === 27) {
32166					e.preventDefault();
32167					if (_this.settings.allowMediaOverlap &&
32168						_this.outer.hasClass('lg-can-toggle') &&
32169						_this.outer.hasClass('lg-components-open')) {
32170						_this.outer.removeClass('lg-components-open');
32171					}
32172					else {
32173						_this.closeGallery();
32174					}
32175				}
32176				if (_this.lgOpened && _this.galleryItems.length > 1) {
32177					if (e.keyCode === 37) {
32178						e.preventDefault();
32179						_this.goToPrevSlide();
32180					}
32181					if (e.keyCode === 39) {
32182						e.preventDefault();
32183						_this.goToNextSlide();
32184					}
32185				}
32186			});
32187		};
32188		LightGallery.prototype.arrow = function () {
32189			var _this = this;
32190			this.getElementById('lg-prev').on('click.lg', function () {
32191				_this.goToPrevSlide();
32192			});
32193			this.getElementById('lg-next').on('click.lg', function () {
32194				_this.goToNextSlide();
32195			});
32196		};
32197		LightGallery.prototype.arrowDisable = function (index) {
32198			// Disable arrows if settings.hideControlOnEnd is true
32199			if (!this.settings.loop && this.settings.hideControlOnEnd) {
32200				var $prev = this.getElementById('lg-prev');
32201				var $next = this.getElementById('lg-next');
32202				if (index + 1 === this.galleryItems.length) {
32203					$next.attr('disabled', 'disabled').addClass('disabled');
32204				}
32205				else {
32206					$next.removeAttr('disabled').removeClass('disabled');
32207				}
32208				if (index === 0) {
32209					$prev.attr('disabled', 'disabled').addClass('disabled');
32210				}
32211				else {
32212					$prev.removeAttr('disabled').removeClass('disabled');
32213				}
32214			}
32215		};
32216		LightGallery.prototype.setTranslate = function ($el, xValue, yValue, scaleX, scaleY) {
32217			if (scaleX === void 0) { scaleX = 1; }
32218			if (scaleY === void 0) { scaleY = 1; }
32219			$el.css('transform', 'translate3d(' +
32220				xValue +
32221				'px, ' +
32222				yValue +
32223				'px, 0px) scale3d(' +
32224				scaleX +
32225				', ' +
32226				scaleY +
32227				', 1)');
32228		};
32229		LightGallery.prototype.mousewheel = function () {
32230			var _this = this;
32231			var lastCall = 0;
32232			this.outer.on('wheel.lg', function (e) {
32233				if (!e.deltaY || _this.galleryItems.length < 2) {
32234					return;
32235				}
32236				e.preventDefault();
32237				var now = new Date().getTime();
32238				if (now - lastCall < 1000) {
32239					return;
32240				}
32241				lastCall = now;
32242				if (e.deltaY > 0) {
32243					_this.goToNextSlide();
32244				}
32245				else if (e.deltaY < 0) {
32246					_this.goToPrevSlide();
32247				}
32248			});
32249		};
32250		LightGallery.prototype.isSlideElement = function (target) {
32251			return (target.hasClass('lg-outer') ||
32252				target.hasClass('lg-item') ||
32253				target.hasClass('lg-img-wrap'));
32254		};
32255		LightGallery.prototype.isPosterElement = function (target) {
32256			var playButton = this.getSlideItem(this.index)
32257				.find('.lg-video-play-button')
32258				.get();
32259			return (target.hasClass('lg-video-poster') ||
32260				target.hasClass('lg-video-play-button') ||
32261				(playButton && playButton.contains(target.get())));
32262		};
32263		/**
32264		 * Maximize minimize inline gallery.
32265		 * @category lGPublicMethods
32266		 */
32267		LightGallery.prototype.toggleMaximize = function () {
32268			var _this = this;
32269			this.getElementById('lg-maximize').on('click.lg', function () {
32270				_this.$container.toggleClass('lg-inline');
32271				_this.refreshOnResize();
32272			});
32273		};
32274		LightGallery.prototype.invalidateItems = function () {
32275			for (var index = 0; index < this.items.length; index++) {
32276				var element = this.items[index];
32277				var $element = $LG(element);
32278				$element.off("click.lgcustom-item-" + $element.attr('data-lg-id'));
32279			}
32280		};
32281		LightGallery.prototype.trapFocus = function () {
32282			var _this = this;
32283			this.$container.get().focus({
32284				preventScroll: true,
32285			});
32286			$LG(window).on("keydown.lg.global" + this.lgId, function (e) {
32287				if (!_this.lgOpened) {
32288					return;
32289				}
32290				var isTabPressed = e.key === 'Tab' || e.keyCode === 9;
32291				if (!isTabPressed) {
32292					return;
32293				}
32294				var focusableEls = utils.getFocusableElements(_this.$container.get());
32295				var firstFocusableEl = focusableEls[0];
32296				var lastFocusableEl = focusableEls[focusableEls.length - 1];
32297				if (e.shiftKey) {
32298					if (document.activeElement === firstFocusableEl) {
32299						lastFocusableEl.focus();
32300						e.preventDefault();
32301					}
32302				}
32303				else {
32304					if (document.activeElement === lastFocusableEl) {
32305						firstFocusableEl.focus();
32306						e.preventDefault();
32307					}
32308				}
32309			});
32310		};
32311		LightGallery.prototype.manageCloseGallery = function () {
32312			var _this = this;
32313			if (!this.settings.closable)
32314				return;
32315			var mousedown = false;
32316			this.getElementById('lg-close').on('click.lg', function () {
32317				_this.closeGallery();
32318			});
32319			if (this.settings.closeOnTap) {
32320				// If you drag the slide and release outside gallery gets close on chrome
32321				// for preventing this check mousedown and mouseup happened on .lg-item or lg-outer
32322				this.outer.on('mousedown.lg', function (e) {
32323					var target = $LG(e.target);
32324					if (_this.isSlideElement(target)) {
32325						mousedown = true;
32326					}
32327					else {
32328						mousedown = false;
32329					}
32330				});
32331				this.outer.on('mousemove.lg', function () {
32332					mousedown = false;
32333				});
32334				this.outer.on('mouseup.lg', function (e) {
32335					var target = $LG(e.target);
32336					if (_this.isSlideElement(target) && mousedown) {
32337						if (!_this.outer.hasClass('lg-dragging')) {
32338							_this.closeGallery();
32339						}
32340					}
32341				});
32342			}
32343		};
32344		/**
32345		 * Close lightGallery if it is opened.
32346		 *
32347		 * @description If closable is false in the settings, you need to pass true via closeGallery method to force close gallery
32348		 * @return returns the estimated time to close gallery completely including the close animation duration
32349		 * @category lGPublicMethods
32350		 * @example
32351		 *  const plugin = lightGallery();
32352		 *  plugin.closeGallery();
32353		 *
32354		 */
32355		LightGallery.prototype.closeGallery = function (force) {
32356			var _this = this;
32357			if (!this.lgOpened || (!this.settings.closable && !force)) {
32358				return 0;
32359			}
32360			this.LGel.trigger(lGEvents.beforeClose);
32361			if (this.settings.resetScrollPosition && !this.settings.hideScrollbar) {
32362				$LG(window).scrollTop(this.prevScrollTop);
32363			}
32364			var currentItem = this.items[this.index];
32365			var transform;
32366			if (this.zoomFromOrigin && currentItem) {
32367				var _a = this.mediaContainerPosition, top_4 = _a.top, bottom = _a.bottom;
32368				var _b = this.galleryItems[this.index], __slideVideoInfo = _b.__slideVideoInfo, poster = _b.poster;
32369				//Uncode edit ##START##
32370				var imageSize = utils.getSize(currentItem, this.outer, top_4 + bottom, __slideVideoInfo && poster && this.settings.videoMaxSize, this.galleryItems[this.index]);
32371				// var imageSize = utils.getSize(currentItem, this.outer, top_4 + bottom, __slideVideoInfo && poster && this.settings.videoMaxSize);
32372				//Uncode edit ##END##
32373				transform = utils.getTransform(currentItem, this.outer, top_4, bottom, imageSize);
32374			}
32375			if (this.zoomFromOrigin && transform) {
32376				this.outer.addClass('lg-closing lg-zoom-from-image');
32377				this.getSlideItem(this.index)
32378					.addClass('lg-start-end-progress')
32379					.css('transition-duration', this.settings.startAnimationDuration + 'ms')
32380					.css('transform', transform);
32381			}
32382			else {
32383				this.outer.addClass('lg-hide-items');
32384				// lg-zoom-from-image is used for setting the opacity to 1 if zoomFromOrigin is true
32385				// If the closing item doesn't have the lg-size attribute, remove this class to avoid the closing css conflicts
32386				this.outer.removeClass('lg-zoom-from-image');
32387			}
32388			// Unbind all events added by lightGallery
32389			// @todo
32390			//this.$el.off('.lg.tm');
32391			this.destroyModules();
32392			this.lGalleryOn = false;
32393			this.isDummyImageRemoved = false;
32394			this.zoomFromOrigin = this.settings.zoomFromOrigin;
32395			clearTimeout(this.hideBarTimeout);
32396			this.hideBarTimeout = false;
32397			$LG('html').removeClass('lg-on');
32398			this.outer.removeClass('lg-visible lg-components-open');
32399			// Resetting opacity to 0 isd required as  vertical swipe to close function adds inline opacity.
32400			this.$backdrop.removeClass('in').css('opacity', 0);
32401			var removeTimeout = this.zoomFromOrigin && transform
32402				? Math.max(this.settings.startAnimationDuration, this.settings.backdropDuration)
32403				: this.settings.backdropDuration;
32404			this.$container.removeClass('lg-show-in');
32405			// Once the closign animation is completed and gallery is invisible
32406			setTimeout(function () {
32407				if (_this.zoomFromOrigin && transform) {
32408					_this.outer.removeClass('lg-zoom-from-image');
32409				}
32410				_this.$container.removeClass('lg-show');
32411				// Reset scrollbar
32412				_this.resetScrollBar();
32413				// Need to remove inline opacity as it is used in the stylesheet as well
32414				_this.$backdrop
32415					.removeAttr('style')
32416					.css('transition-duration', _this.settings.backdropDuration + 'ms');
32417				_this.outer.removeClass("lg-closing " + _this.settings.startClass);
vendor: 6,259 bytes, lines 32418-32621
32418				_this.getSlideItem(_this.index).removeClass('lg-start-end-progress');
32419				_this.$inner.empty();
32420				if (_this.lgOpened) {
32421					_this.LGel.trigger(lGEvents.afterClose, {
32422						instance: _this,
32423					});
32424				}
32425				if (_this.$container.get()) {
32426					_this.$container.get().blur();
32427				}
32428				_this.lgOpened = false;
32429			}, removeTimeout + 100);
32430			return removeTimeout + 100;
32431		};
32432		LightGallery.prototype.initModules = function () {
32433			this.plugins.forEach(function (module) {
32434				try {
32435					module.init();
32436				}
32437				catch (err) {
32438					console.warn("lightGallery:- make sure lightGallery module is properly initiated");
32439				}
32440			});
32441		};
32442		LightGallery.prototype.destroyModules = function (destroy) {
32443			this.plugins.forEach(function (module) {
32444				try {
32445					if (destroy) {
32446						module.destroy();
32447					}
32448					else {
32449						module.closeGallery && module.closeGallery();
32450					}
32451				}
32452				catch (err) {
32453					console.warn("lightGallery:- make sure lightGallery module is properly destroyed");
32454				}
32455			});
32456		};
32457		/**
32458		 * Refresh lightGallery with new set of children.
32459		 *
32460		 * @description This is useful to update the gallery when the child elements are changed without calling destroy method.
32461		 *
32462		 * If you are using dynamic mode, you can pass the modified array of dynamicEl as the first parameter to refresh the dynamic gallery
32463		 * @see <a href="/demos/dynamic-mode/">Demo</a>
32464		 * @category lGPublicMethods
32465		 * @example
32466		 *  const plugin = lightGallery();
32467		 *  // Delete or add children, then call
32468		 *  plugin.refresh();
32469		 *
32470		 */
32471		LightGallery.prototype.refresh = function (galleryItems) {
32472			if (!this.settings.dynamic) {
32473				this.invalidateItems();
32474			}
32475			if (galleryItems) {
32476				this.galleryItems = galleryItems;
32477			}
32478			else {
32479				this.galleryItems = this.getItems();
32480			}
32481			this.updateControls();
32482			this.openGalleryOnItemClick();
32483			this.LGel.trigger(lGEvents.updateSlides);
32484		};
32485		LightGallery.prototype.updateControls = function () {
32486			this.addSlideVideoInfo(this.galleryItems);
32487			this.updateCounterTotal();
32488			this.manageSingleSlideClassName();
32489		};
32490		/**
32491		 * Destroy lightGallery.
32492		 * Destroy lightGallery and its plugin instances completely
32493		 *
32494		 * @description This method also calls CloseGallery function internally. Returns the time takes to completely close and destroy the instance.
32495		 * In case if you want to re-initialize lightGallery right after destroying it, initialize it only once the destroy process is completed.
32496		 * You can use refresh method most of the times.
32497		 * @category lGPublicMethods
32498		 * @example
32499		 *  const plugin = lightGallery();
32500		 *  plugin.destroy();
32501		 *
32502		 */
32503		LightGallery.prototype.destroy = function () {
32504			var _this = this;
32505			var closeTimeout = this.closeGallery(true);
32506			setTimeout(function () {
32507				_this.destroyModules(true);
32508				if (!_this.settings.dynamic) {
32509					_this.invalidateItems();
32510				}
32511				$LG(window).off(".lg.global" + _this.lgId);
32512				_this.LGel.off('.lg');
32513				_this.$container.remove();
32514			}, closeTimeout);
32515			return closeTimeout;
32516		};
32517		return LightGallery;
32518	}());
32519
32520	function lightGallery(el, options) {
32521		return new LightGallery(el, options);
32522	}
32523
32524	return lightGallery;
32525
32526})));
32527
32528/*!
32529 * lightgallery | 2.5.0 | June 13th 2022
32530 * http://www.lightgalleryjs.com/
32531 * Copyright (c) 2020 Sachin Neravath;
32532 * @license GPLv3
32533 */
32534
32535(function (global, factory) {
32536	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
32537	typeof define === 'function' && define.amd ? define(factory) :
32538	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgZoom = factory());
32539}(this, (function () { 'use strict';
32540
32541	/*! *****************************************************************************
32542	Copyright (c) Microsoft Corporation.
32543
32544	Permission to use, copy, modify, and/or distribute this software for any
32545	purpose with or without fee is hereby granted.
32546
32547	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
32548	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
32549	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
32550	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
32551	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
32552	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
32553	PERFORMANCE OF THIS SOFTWARE.
32554	***************************************************************************** */
32555
32556	var __assign = function() {
32557		__assign = Object.assign || function __assign(t) {
32558			for (var s, i = 1, n = arguments.length; i < n; i++) {
32559				s = arguments[i];
32560				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
32561			}
32562			return t;
32563		};
32564		return __assign.apply(this, arguments);
32565	};
32566
32567	var zoomSettings = {
32568		scale: 1,
32569		zoom: true,
32570		actualSize: true,
32571		showZoomInOutIcons: false,
32572		actualSizeIcons: {
32573			zoomIn: 'lg-zoom-in',
32574			zoomOut: 'lg-zoom-out',
32575		},
32576		enableZoomAfter: 300,
32577		zoomPluginStrings: {
32578			zoomIn: 'Zoom in',
32579			zoomOut: 'Zoom out',
32580			viewActualSize: 'View actual size',
32581		},
32582	};
32583
32584	/**
32585	 * List of lightGallery events
32586	 * All events should be documented here
32587	 * Below interfaces are used to build the website documentations
32588	 * */
32589	var lGEvents = {
32590		afterAppendSlide: 'lgAfterAppendSlide',
32591		init: 'lgInit',
32592		hasVideo: 'lgHasVideo',
32593		containerResize: 'lgContainerResize',
32594		updateSlides: 'lgUpdateSlides',
32595		afterAppendSubHtml: 'lgAfterAppendSubHtml',
32596		beforeOpen: 'lgBeforeOpen',
32597		afterOpen: 'lgAfterOpen',
32598		slideItemLoad: 'lgSlideItemLoad',
32599		beforeSlide: 'lgBeforeSlide',
32600		afterSlide: 'lgAfterSlide',
32601		posterClick: 'lgPosterClick',
32602		dragStart: 'lgDragStart',
32603		dragMove: 'lgDragMove',
32604		dragEnd: 'lgDragEnd',
32605		beforeNextSlide: 'lgBeforeNextSlide',
32606		beforePrevSlide: 'lgBeforePrevSlide',
32607		beforeClose: 'lgBeforeClose',
32608		afterClose: 'lgAfterClose',
32609		rotateLeft: 'lgRotateLeft',
32610		rotateRight: 'lgRotateRight',
32611		flipHorizontal: 'lgFlipHorizontal',
32612		flipVertical: 'lgFlipVertical',
32613		autoplay: 'lgAutoplay',
32614		autoplayStart: 'lgAutoplayStart',
32615		autoplayStop: 'lgAutoplayStop',
32616	};
32617
32618	var Zoom = /** @class */ (function () {
32619		function Zoom(instance, $LG) {
32620			// get lightGallery core plugin instance
32621			this.core = instance;
32622			this.$LG = $LG;
32623			this.settings = __assign(__assign({}, zoomSettings), this.core.settings);
32624			return this;
32625		}
32626		// Append Zoom controls. Actual size, Zoom-in, Zoom-out
32627		Zoom.prototype.buildTemplates = function () {
32628			var zoomIcons = this.settings.showZoomInOutIcons
32629				? "<button id=\"" + this.core.getIdName('lg-zoom-in') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomIn'] + "\" class=\"lg-zoom-in lg-icon\"></button><button id=\"" + this.core.getIdName('lg-zoom-out') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['zoomIn'] + "\" class=\"lg-zoom-out lg-icon\"></button>"
32630				: '';
32631			if (this.settings.actualSize) {
32632				zoomIcons += "<button id=\"" + this.core.getIdName('lg-actual-size') + "\" type=\"button\" aria-label=\"" + this.settings.zoomPluginStrings['viewActualSize'] + "\" class=\"" + this.settings.actualSizeIcons.zoomIn + " lg-icon\"></button>";
32633			}
32634			this.core.outer.addClass('lg-use-transition-for-zoom');
32635			this.core.$toolbar.first().append(zoomIcons);
32636		};
32637		/**
32638		 * @desc Enable zoom option only once the image is completely loaded
32639		 * If zoomFromOrigin is true, Zoom is enabled once the dummy image has been inserted
32640		 *
32641		 * Zoom styles are defined under lg-zoomable CSS class.
32642		 */
32643		Zoom.prototype.enableZoom = function (event) {
32644			var _this = this;
32645			// delay will be 0 except first time
32646			var _speed = this.settings.enableZoomAfter + event.detail.delay;
32647			// set _speed value 0 if gallery opened from direct url and if it is first slide
32648			if (this.$LG('body').first().hasClass('lg-from-hash') &&
32649				event.detail.delay) {
32650				// will execute only once
32651				_speed = 0;
32652			}
32653			else {
32654				// Remove lg-from-hash to enable starting animation.
32655				this.$LG('body').first().removeClass('lg-from-hash');
32656			}
32657			this.zoomableTimeout = setTimeout(function () {
32658				if (!_this.isImageSlide()) {
32659					return;
32660				}
32661				_this.core.getSlideItem(event.detail.index).addClass('lg-zoomable');
32662				if (event.detail.index === _this.core.index) {
32663					_this.setZoomEssentials();
32664				}
32665			}, _speed + 30);
32666		};
32667		Zoom.prototype.enableZoomOnSlideItemLoad = function () {
32668			// Add zoomable class
32669			this.core.LGel.on(lGEvents.slideItemLoad + ".zoom", this.enableZoom.bind(this));
32670		};
32671		Zoom.prototype.getModifier = function (rotateValue, axis, el) {
32672			var originalRotate = rotateValue;
32673			rotateValue = Math.abs(rotateValue);
32674			var transformValues = this.getCurrentTransform(el);
32675			if (!transformValues) {
32676				return 1;
32677			}
32678			var modifier = 1;
32679			if (axis === 'X') {
32680				var flipHorizontalValue = Math.sign(parseFloat(transformValues[0]));
32681				if (rotateValue === 0 || rotateValue === 180) {
32682					modifier = 1;
32683				}
32684				else if (rotateValue === 90) {
32685					if ((originalRotate === -90 && flipHorizontalValue === 1) ||
32686						(originalRotate === 90 && flipHorizontalValue === -1)) {
32687						modifier = -1;
32688					}
32689					else {
32690						modifier = 1;
32691					}
32692				}
32693				modifier = modifier * flipHorizontalValue;
32694			}
32695			else {
32696				var flipVerticalValue = Math.sign(parseFloat(transformValues[3]));
32697				if (rotateValue === 0 || rotateValue === 180) {
32698					modifier = 1;
32699				}
32700				else if (rotateValue === 90) {
32701					var sinX = parseFloat(transformValues[1]);
32702					var sinMinusX = parseFloat(transformValues[2]);
32703					modifier = Math.sign(sinX * sinMinusX * originalRotate * flipVerticalValue);
32704				}
32705				modifier = modifier * flipVerticalValue;
32706			}
32707			return modifier;
32708		};
32709		Zoom.prototype.getImageSize = function ($image, rotateValue, axis) {
32710			var imageSizes = {
32711				y: 'offsetHeight',
32712				x: 'offsetWidth',
32713			};
32714			if (Math.abs(rotateValue) === 90) {
32715				// Swap axis
32716				if (axis === 'x') {
32717					axis = 'y';
32718				}
32719				else {
32720					axis = 'x';
32721				}
32722			}
32723			return $image[imageSizes[axis]];
32724		};
32725		Zoom.prototype.getDragCords = function (e, rotateValue) {
32726			if (rotateValue === 90) {
32727				return {
32728					x: e.pageY,
32729					y: e.pageX,
32730				};
32731			}
32732			else {
32733				return {
32734					x: e.pageX,
32735					y: e.pageY,
32736				};
32737			}
32738		};
32739		Zoom.prototype.getSwipeCords = function (e, rotateValue) {
32740			var x = e.targetTouches[0].pageX;
32741			var y = e.targetTouches[0].pageY;
32742			if (rotateValue === 90) {
32743				return {
32744					x: y,
32745					y: x,
32746				};
32747			}
32748			else {
32749				return {
32750					x: x,
32751					y: y,
32752				};
32753			}
32754		};
32755		Zoom.prototype.getDragAllowedAxises = function (rotateValue, scale) {
32756			scale = scale || this.scale || 1;
32757			var allowY = this.imageYSize * scale > this.containerRect.height;
32758			var allowX = this.imageXSize * scale > this.containerRect.width;
32759			if (rotateValue === 90) {
32760				return {
32761					allowX: allowY,
32762					allowY: allowX,
32763				};
32764			}
32765			else {
32766				return {
32767					allowX: allowX,
32768					allowY: allowY,
32769				};
32770			}
32771		};
32772		/**
32773		 *
32774		 * @param {Element} el
32775		 * @return matrix(cos(X), sin(X), -sin(X), cos(X), 0, 0);
32776		 * Get the current transform value
32777		 */
32778		Zoom.prototype.getCurrentTransform = function (el) {
32779			if (!el) {
32780				return;
32781			}
32782			var st = window.getComputedStyle(el, null);
32783			var tm = st.getPropertyValue('-webkit-transform') ||
32784				st.getPropertyValue('-moz-transform') ||
32785				st.getPropertyValue('-ms-transform') ||
32786				st.getPropertyValue('-o-transform') ||
32787				st.getPropertyValue('transform') ||
32788				'none';
32789			if (tm !== 'none') {
32790				return tm.split('(')[1].split(')')[0].split(',');
32791			}
32792			return;
32793		};
32794		Zoom.prototype.getCurrentRotation = function (el) {
32795			if (!el) {
32796				return 0;
32797			}
32798			var values = this.getCurrentTransform(el);
32799			if (values) {
32800				return Math.round(Math.atan2(parseFloat(values[1]), parseFloat(values[0])) *
32801					(180 / Math.PI));
32802				// If you want rotate in 360
32803				//return (angle < 0 ? angle + 360 : angle);
32804			}
32805			return 0;
32806		};
32807		Zoom.prototype.setZoomEssentials = function () {
32808			var $image = this.core
32809				.getSlideItem(this.core.index)
32810				.find('.lg-image')
32811				.first();
32812			var rotateEl = this.core
32813				.getSlideItem(this.core.index)
32814				.find('.lg-img-rotate')
32815				.first()
32816				.get();
32817			this.rotateValue = this.getCurrentRotation(rotateEl);
32818			this.imageYSize = this.getImageSize($image.get(), this.rotateValue, 'y');
32819			this.imageXSize = this.getImageSize($image.get(), this.rotateValue, 'x');
32820			this.containerRect = this.core.outer.get().getBoundingClientRect();
32821			this.modifierX = this.getModifier(this.rotateValue, 'X', rotateEl);
32822			this.modifierY = this.getModifier(this.rotateValue, 'Y', rotateEl);
32823		};
32824		/**
32825		 * @desc Image zoom
32826		 * Translate the wrap and scale the image to get better user experience
32827		 *
32828		 * @param {String} scale - Zoom decrement/increment value
32829		 */
32830		Zoom.prototype.zoomImage = function (scale) {
32831			// Find offset manually to avoid issue after zoom
32832			var offsetX = (this.containerRect.width - this.imageXSize) / 2 +
32833				this.containerRect.left;
32834			var _a = this.core.mediaContainerPosition, top = _a.top, bottom = _a.bottom;
32835			var topBottomSpacing = Math.abs(top - bottom) / 2;
32836			var offsetY = (this.containerRect.height -
32837				this.imageYSize -
32838				topBottomSpacing * this.modifierX) /
32839				2 +
32840				this.scrollTop +
32841				this.containerRect.top;
32842			var originalX;
32843			var originalY;
32844			if (scale === 1) {
32845				this.positionChanged = false;
32846			}
32847			var dragAllowedAxises = this.getDragAllowedAxises(Math.abs(this.rotateValue), scale);
32848			var allowY = dragAllowedAxises.allowY, allowX = dragAllowedAxises.allowX;
32849			if (this.positionChanged) {
32850				originalX = this.left / (this.scale - 1);
32851				originalY = this.top / (this.scale - 1);
32852				this.pageX = Math.abs(originalX) + offsetX;
32853				this.pageY = Math.abs(originalY) + offsetY;
32854				this.positionChanged = false;
32855			}
32856			var possibleSwipeCords = this.getPossibleSwipeDragCords(this.rotateValue, scale);
32857			var _x = offsetX - this.pageX;
32858			var _y = offsetY - this.pageY;
32859			var x = (scale - 1) * _x;
32860			var y = (scale - 1) * _y;
32861			if (allowX) {
32862				if (this.isBeyondPossibleLeft(x, possibleSwipeCords.minX)) {
32863					x = possibleSwipeCords.minX;
32864				}
32865				else if (this.isBeyondPossibleRight(x, possibleSwipeCords.maxX)) {
32866					x = possibleSwipeCords.maxX;
32867				}
32868			}
32869			else {
32870				if (scale > 1) {
32871					if (x < possibleSwipeCords.minX) {
32872						x = possibleSwipeCords.minX;
32873					}
32874					else if (x > possibleSwipeCords.maxX) {
32875						x = possibleSwipeCords.maxX;
32876					}
32877				}
32878			}
32879			if (allowY) {
32880				if (this.isBeyondPossibleTop(y, possibleSwipeCords.minY)) {
32881					y = possibleSwipeCords.minY;
32882				}
32883				else if (this.isBeyondPossibleBottom(y, possibleSwipeCords.maxY)) {
32884					y = possibleSwipeCords.maxY;
32885				}
32886			}
32887			else {
32888				// If the translate value based on index of beyond the viewport, utilize the available space to prevent image being cut out
32889				if (scale > 1) {
32890					//If image goes beyond viewport top, use the minim possible translate value
32891					if (y < possibleSwipeCords.minY) {
32892						y = possibleSwipeCords.minY;
32893					}
32894					else if (y > possibleSwipeCords.maxY) {
32895						y = possibleSwipeCords.maxY;
32896					}
32897				}
32898			}
32899			this.setZoomStyles({
32900				x: x,
32901				y: y,
32902				scale: scale,
32903			});
32904		};
32905		/**
32906		 * @desc apply scale3d to image and translate to image wrap
32907		 * @param {style} X,Y and scale
32908		 */
32909		Zoom.prototype.setZoomStyles = function (style) {
32910			var $image = this.core
32911				.getSlideItem(this.core.index)
32912				.find('.lg-image')
32913				.first();
32914			var $dummyImage = this.core.outer
32915				.find('.lg-current .lg-dummy-img')
32916				.first();
32917			var $imageWrap = $image.parent();
32918			this.scale = style.scale;
32919			$image.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
32920			$dummyImage.css('transform', 'scale3d(' + style.scale + ', ' + style.scale + ', 1)');
32921			var transform = 'translate3d(' + style.x + 'px, ' + style.y + 'px, 0)';
32922			$imageWrap.css('transform', transform);
32923			this.left = style.x;
32924			this.top = style.y;
32925		};
32926		/**
32927		 * @param index - Index of the current slide
32928		 * @param event - event will be available only if the function is called on clicking/taping the imags
32929		 */
32930		Zoom.prototype.setActualSize = function (index, event) {
32931			var _this = this;
32932			// Allow zoom only on image
32933			if (!this.isImageSlide() ||
32934				this.core.outer.hasClass('lg-first-slide-loading')) {
32935				return;
32936			}
32937			var scale = this.getCurrentImageActualSizeScale();
32938			if (this.core.outer.hasClass('lg-zoomed')) {
32939				this.scale = 1;
32940			}
32941			else {
32942				this.scale = this.getScale(scale);
32943			}
32944			this.setPageCords(event);
32945			this.beginZoom(this.scale);
32946			this.zoomImage(this.scale);
32947			setTimeout(function () {
32948				_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
32949			}, 10);
32950		};
32951		Zoom.prototype.getNaturalWidth = function (index) {
32952			var $image = this.core.getSlideItem(index).find('.lg-image').first();
32953			var naturalWidth = this.core.galleryItems[index].width;
32954			return naturalWidth
32955				? parseFloat(naturalWidth)
32956				: $image.get().naturalWidth;
32957		};
32958		Zoom.prototype.getActualSizeScale = function (naturalWidth, width) {
32959			var _scale;
32960			var scale;
32961			if (naturalWidth > width) {
32962				_scale = naturalWidth / width;
32963				scale = _scale || 2;
32964			}
32965			else {
32966				scale = 1;
32967			}
32968			return scale;
32969		};
32970		Zoom.prototype.getCurrentImageActualSizeScale = function () {
32971			var $image = this.core
32972				.getSlideItem(this.core.index)
32973				.find('.lg-image')
32974				.first();
32975			var width = $image.get().offsetWidth;
32976			var naturalWidth = this.getNaturalWidth(this.core.index) || width;
32977			return this.getActualSizeScale(naturalWidth, width);
32978		};
32979		Zoom.prototype.getPageCords = function (event) {
32980			var cords = {};
32981			if (event) {
32982				cords.x = event.pageX || event.targetTouches[0].pageX;
32983				cords.y = event.pageY || event.targetTouches[0].pageY;
32984			}
32985			else {
32986				var containerRect = this.core.outer.get().getBoundingClientRect();
32987				cords.x = containerRect.width / 2 + containerRect.left;
32988				cords.y =
32989					containerRect.height / 2 + this.scrollTop + containerRect.top;
32990			}
32991			return cords;
32992		};
32993		Zoom.prototype.setPageCords = function (event) {
32994			var pageCords = this.getPageCords(event);
32995			this.pageX = pageCords.x;
32996			this.pageY = pageCords.y;
32997		};
32998		// If true, zoomed - in else zoomed out
32999		Zoom.prototype.beginZoom = function (scale) {
33000			this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
33001			if (scale > 1) {
33002				this.core.outer.addClass('lg-zoomed');
33003				var $actualSize = this.core.getElementById('lg-actual-size');
33004				$actualSize
33005					.removeClass(this.settings.actualSizeIcons.zoomIn)
33006					.addClass(this.settings.actualSizeIcons.zoomOut);
33007			}
33008			else {
33009				this.resetZoom();
33010			}
33011			return scale > 1;
33012		};
33013		Zoom.prototype.getScale = function (scale) {
33014			var actualSizeScale = this.getCurrentImageActualSizeScale();
33015			if (scale < 1) {
33016				scale = 1;
33017			}
33018			else if (scale > actualSizeScale) {
33019				scale = actualSizeScale;
33020			}
33021			return scale;
33022		};
33023		Zoom.prototype.init = function () {
33024			var _this = this;
33025			if (!this.settings.zoom) {
33026				return;
33027			}
33028			this.buildTemplates();
33029			this.enableZoomOnSlideItemLoad();
33030			var tapped = null;
33031			this.core.outer.on('dblclick.lg', function (event) {
33032				if (!_this.$LG(event.target).hasClass('lg-image')) {
33033					return;
33034				}
33035				_this.setActualSize(_this.core.index, event);
33036			});
33037			this.core.outer.on('touchstart.lg', function (event) {
33038				var $target = _this.$LG(event.target);
33039				if (event.targetTouches.length === 1 &&
33040					$target.hasClass('lg-image')) {
33041					if (!tapped) {
33042						tapped = setTimeout(function () {
33043							tapped = null;
33044						}, 300);
33045					}
33046					else {
33047						clearTimeout(tapped);
33048						tapped = null;
33049						event.preventDefault();
33050						_this.setActualSize(_this.core.index, event);
33051					}
33052				}
33053			});
33054			// Update zoom on resize and orientationchange
33055			this.core.LGel.on(lGEvents.containerResize + ".zoom " + lGEvents.rotateRight + ".zoom " + lGEvents.rotateLeft + ".zoom " + lGEvents.flipHorizontal + ".zoom " + lGEvents.flipVertical + ".zoom", function () {
33056				if (!_this.core.lgOpened || !_this.isImageSlide())
33057					return;
33058				_this.setPageCords();
33059				_this.setZoomEssentials();
33060				_this.zoomImage(_this.scale);
33061			});
33062			// Update zoom on resize and orientationchange
33063			this.$LG(window).on("scroll.lg.zoom.global" + this.core.lgId, function () {
33064				if (!_this.core.lgOpened)
33065					return;
33066				_this.scrollTop = _this.$LG(window).scrollTop();
33067			});
33068			this.core.getElementById('lg-zoom-out').on('click.lg', function () {
33069				if (_this.core.outer.find('.lg-current .lg-image').get()) {
33070					_this.scale -= _this.settings.scale;
33071					_this.scale = _this.getScale(_this.scale);
33072					_this.beginZoom(_this.scale);
33073					_this.zoomImage(_this.scale);
33074				}
33075			});
33076			this.core.getElementById('lg-zoom-in').on('click.lg', function () {
33077				_this.zoomIn();
33078			});
33079			this.core.getElementById('lg-actual-size').on('click.lg', function () {
33080				_this.setActualSize(_this.core.index);
33081			});
33082			this.core.LGel.on(lGEvents.beforeOpen + ".zoom", function () {
33083				_this.core.outer.find('.lg-item').removeClass('lg-zoomable');
33084			});
33085			this.core.LGel.on(lGEvents.afterOpen + ".zoom", function () {
33086				_this.scrollTop = _this.$LG(window).scrollTop();
33087				// Set the initial value center
33088				_this.pageX = _this.core.outer.width() / 2;
33089				_this.pageY = _this.core.outer.height() / 2 + _this.scrollTop;
33090				_this.scale = 1;
33091			});
33092			// Reset zoom on slide change
33093			this.core.LGel.on(lGEvents.afterSlide + ".zoom", function (event) {
33094				var prevIndex = event.detail.prevIndex;
33095				_this.scale = 1;
33096				_this.positionChanged = false;
33097				_this.resetZoom(prevIndex);
33098				if (_this.isImageSlide()) {
33099					_this.setZoomEssentials();
33100				}
33101			});
33102			// Drag option after zoom
33103			this.zoomDrag();
33104			this.pinchZoom();
33105			this.zoomSwipe();
33106			// Store the zoomable timeout value just to clear it while closing
33107			this.zoomableTimeout = false;
33108			this.positionChanged = false;
33109		};
33110		Zoom.prototype.zoomIn = function (scale) {
33111			// Allow zoom only on image
33112			if (!this.isImageSlide()) {
33113				return;
33114			}
33115			if (scale) {
33116				this.scale = scale;
33117			}
33118			else {
33119				this.scale += this.settings.scale;
33120			}
33121			this.scale = this.getScale(this.scale);
33122			this.beginZoom(this.scale);
33123			this.zoomImage(this.scale);
33124		};
33125		// Reset zoom effect
33126		Zoom.prototype.resetZoom = function (index) {
33127			this.core.outer.removeClass('lg-zoomed lg-zoom-drag-transition');
33128			var $actualSize = this.core.getElementById('lg-actual-size');
33129			var $item = this.core.getSlideItem(index !== undefined ? index : this.core.index);
33130			$actualSize
33131				.removeClass(this.settings.actualSizeIcons.zoomOut)
33132				.addClass(this.settings.actualSizeIcons.zoomIn);
33133			$item.find('.lg-img-wrap').first().removeAttr('style');
33134			$item.find('.lg-image').first().removeAttr('style');
33135			this.scale = 1;
33136			this.left = 0;
33137			this.top = 0;
33138			// Reset pagx pagy values to center
33139			this.setPageCords();
33140		};
33141		Zoom.prototype.getTouchDistance = function (e) {
33142			return Math.sqrt((e.targetTouches[0].pageX - e.targetTouches[1].pageX) *
33143				(e.targetTouches[0].pageX - e.targetTouches[1].pageX) +
33144				(e.targetTouches[0].pageY - e.targetTouches[1].pageY) *
33145					(e.targetTouches[0].pageY - e.targetTouches[1].pageY));
33146		};
33147		Zoom.prototype.pinchZoom = function () {
33148			var _this = this;
33149			var startDist = 0;
33150			var pinchStarted = false;
33151			var initScale = 1;
33152			var $item = this.core.getSlideItem(this.core.index);
33153			this.core.$inner.on('touchstart.lg', function (e) {
33154				$item = _this.core.getSlideItem(_this.core.index);
33155				if (!_this.isImageSlide()) {
33156					return;
33157				}
33158				if (e.targetTouches.length === 2 &&
33159					!_this.core.outer.hasClass('lg-first-slide-loading') &&
33160					(_this.$LG(e.target).hasClass('lg-item') ||
33161						$item.get().contains(e.target))) {
33162					initScale = _this.scale || 1;
33163					_this.core.outer.removeClass('lg-zoom-drag-transition lg-zoom-dragging');
33164					_this.core.touchAction = 'pinch';
33165					startDist = _this.getTouchDistance(e);
33166				}
33167			});
33168			this.core.$inner.on('touchmove.lg', function (e) {
33169				if (e.targetTouches.length === 2 &&
33170					_this.core.touchAction === 'pinch' &&
33171					(_this.$LG(e.target).hasClass('lg-item') ||
33172						$item.get().contains(e.target))) {
33173					e.preventDefault();
33174					var endDist = _this.getTouchDistance(e);
33175					var distance = startDist - endDist;
33176					if (!pinchStarted && Math.abs(distance) > 5) {
33177						pinchStarted = true;
33178					}
33179					if (pinchStarted) {
33180						_this.scale = Math.max(1, initScale + -distance * 0.008);
33181						_this.zoomImage(_this.scale);
33182					}
33183				}
33184			});
33185			this.core.$inner.on('touchend.lg', function (e) {
33186				if (_this.core.touchAction === 'pinch' &&
33187					(_this.$LG(e.target).hasClass('lg-item') ||
33188						$item.get().contains(e.target))) {
33189					pinchStarted = false;
33190					startDist = 0;
33191					if (_this.scale <= 1) {
33192						_this.resetZoom();
33193					}
33194					else {
33195						_this.scale = _this.getScale(_this.scale);
33196						_this.zoomImage(_this.scale);
33197						_this.core.outer.addClass('lg-zoomed');
33198					}
33199					_this.core.touchAction = undefined;
33200				}
33201			});
33202		};
33203		Zoom.prototype.touchendZoom = function (startCoords, endCoords, allowX, allowY, touchDuration, rotateValue) {
33204			var distanceXnew = endCoords.x - startCoords.x;
33205			var distanceYnew = endCoords.y - startCoords.y;
33206			var speedX = Math.abs(distanceXnew) / touchDuration + 1;
33207			var speedY = Math.abs(distanceYnew) / touchDuration + 1;
33208			if (speedX > 2) {
33209				speedX += 1;
33210			}
33211			if (speedY > 2) {
33212				speedY += 1;
33213			}
33214			distanceXnew = distanceXnew * speedX;
33215			distanceYnew = distanceYnew * speedY;
33216			var _LGel = this.core
33217				.getSlideItem(this.core.index)
33218				.find('.lg-img-wrap')
33219				.first();
33220			var distance = {};
33221			distance.x = this.left + distanceXnew * this.modifierX;
33222			distance.y = this.top + distanceYnew * this.modifierY;
33223			var possibleSwipeCords = this.getPossibleSwipeDragCords(rotateValue);
33224			if (Math.abs(distanceXnew) > 15 || Math.abs(distanceYnew) > 15) {
33225				if (allowY) {
33226					if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
33227						distance.y = possibleSwipeCords.minY;
33228					}
33229					else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
33230						distance.y = possibleSwipeCords.maxY;
33231					}
33232				}
33233				if (allowX) {
33234					if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
33235						distance.x = possibleSwipeCords.minX;
33236					}
33237					else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
33238						distance.x = possibleSwipeCords.maxX;
33239					}
33240				}
33241				if (allowY) {
33242					this.top = distance.y;
33243				}
33244				else {
33245					distance.y = this.top;
33246				}
33247				if (allowX) {
33248					this.left = distance.x;
33249				}
33250				else {
33251					distance.x = this.left;
33252				}
33253				this.setZoomSwipeStyles(_LGel, distance);
33254				this.positionChanged = true;
33255			}
33256		};
33257		Zoom.prototype.getZoomSwipeCords = function (startCoords, endCoords, allowX, allowY, possibleSwipeCords) {
33258			var distance = {};
33259			if (allowY) {
33260				distance.y =
33261					this.top + (endCoords.y - startCoords.y) * this.modifierY;
33262				if (this.isBeyondPossibleTop(distance.y, possibleSwipeCords.minY)) {
33263					var diffMinY = possibleSwipeCords.minY - distance.y;
33264					distance.y = possibleSwipeCords.minY - diffMinY / 6;
33265				}
33266				else if (this.isBeyondPossibleBottom(distance.y, possibleSwipeCords.maxY)) {
33267					var diffMaxY = distance.y - possibleSwipeCords.maxY;
33268					distance.y = possibleSwipeCords.maxY + diffMaxY / 6;
33269				}
33270			}
33271			else {
33272				distance.y = this.top;
33273			}
33274			if (allowX) {
33275				distance.x =
33276					this.left + (endCoords.x - startCoords.x) * this.modifierX;
33277				if (this.isBeyondPossibleLeft(distance.x, possibleSwipeCords.minX)) {
33278					var diffMinX = possibleSwipeCords.minX - distance.x;
33279					distance.x = possibleSwipeCords.minX - diffMinX / 6;
33280				}
33281				else if (this.isBeyondPossibleRight(distance.x, possibleSwipeCords.maxX)) {
33282					var difMaxX = distance.x - possibleSwipeCords.maxX;
33283					distance.x = possibleSwipeCords.maxX + difMaxX / 6;
33284				}
33285			}
33286			else {
33287				distance.x = this.left;
33288			}
33289			return distance;
33290		};
33291		Zoom.prototype.isBeyondPossibleLeft = function (x, minX) {
33292			return x >= minX;
33293		};
33294		Zoom.prototype.isBeyondPossibleRight = function (x, maxX) {
33295			return x <= maxX;
33296		};
33297		Zoom.prototype.isBeyondPossibleTop = function (y, minY) {
33298			return y >= minY;
33299		};
33300		Zoom.prototype.isBeyondPossibleBottom = function (y, maxY) {
33301			return y <= maxY;
33302		};
33303		Zoom.prototype.isImageSlide = function () {
33304			var currentItem = this.core.galleryItems[this.core.index];
33305			return this.core.getSlideType(currentItem) === 'image';
33306		};
33307		Zoom.prototype.getPossibleSwipeDragCords = function (rotateValue, scale) {
33308			var dataScale = scale || this.scale || 1;
33309			var elDataScale = Math.abs(dataScale);
33310			var _a = this.core.mediaContainerPosition, top = _a.top, bottom = _a.bottom;
33311			var topBottomSpacing = Math.abs(top - bottom) / 2;
33312			var minY = (this.imageYSize - this.containerRect.height) / 2 +
33313				topBottomSpacing * this.modifierX;
33314			var maxY = this.containerRect.height - this.imageYSize * elDataScale + minY;
33315			var minX = (this.imageXSize - this.containerRect.width) / 2;
33316			var maxX = this.containerRect.width - this.imageXSize * elDataScale + minX;
33317			var possibleSwipeCords = {
33318				minY: minY,
33319				maxY: maxY,
33320				minX: minX,
33321				maxX: maxX,
33322			};
33323			if (Math.abs(rotateValue) === 90) {
33324				possibleSwipeCords = {
33325					minY: minX,
33326					maxY: maxX,
33327					minX: minY,
33328					maxX: maxY,
33329				};
33330			}
33331			return possibleSwipeCords;
33332		};
33333		Zoom.prototype.setZoomSwipeStyles = function (LGel, distance) {
33334			LGel.css('transform', 'translate3d(' + distance.x + 'px, ' + distance.y + 'px, 0)');
33335		};
33336		Zoom.prototype.zoomSwipe = function () {
33337			var _this = this;
33338			var startCoords = {};
33339			var endCoords = {};
33340			var isMoved = false;
33341			// Allow x direction drag
33342			var allowX = false;
33343			// Allow Y direction drag
33344			var allowY = false;
33345			var startTime = new Date();
33346			var endTime = new Date();
33347			var possibleSwipeCords;
33348			var _LGel;
33349			var $item = this.core.getSlideItem(this.core.index);
33350			this.core.$inner.on('touchstart.lg', function (e) {
33351				// Allow zoom only on image
33352				if (!_this.isImageSlide()) {
33353					return;
33354				}
33355				$item = _this.core.getSlideItem(_this.core.index);
33356				if ((_this.$LG(e.target).hasClass('lg-item') ||
33357					$item.get().contains(e.target)) &&
33358					e.targetTouches.length === 1 &&
33359					_this.core.outer.hasClass('lg-zoomed')) {
33360					e.preventDefault();
33361					startTime = new Date();
33362					_this.core.touchAction = 'zoomSwipe';
33363					_LGel = _this.core
33364						.getSlideItem(_this.core.index)
33365						.find('.lg-img-wrap')
33366						.first();
33367					var dragAllowedAxises = _this.getDragAllowedAxises(Math.abs(_this.rotateValue));
33368					allowY = dragAllowedAxises.allowY;
33369					allowX = dragAllowedAxises.allowX;
33370					if (allowX || allowY) {
33371						startCoords = _this.getSwipeCords(e, Math.abs(_this.rotateValue));
33372					}
33373					possibleSwipeCords = _this.getPossibleSwipeDragCords(_this.rotateValue);
33374					// reset opacity and transition duration
33375					_this.core.outer.addClass('lg-zoom-dragging lg-zoom-drag-transition');
33376				}
33377			});
33378			this.core.$inner.on('touchmove.lg', function (e) {
33379				if (e.targetTouches.length === 1 &&
33380					_this.core.touchAction === 'zoomSwipe' &&
33381					(_this.$LG(e.target).hasClass('lg-item') ||
33382						$item.get().contains(e.target))) {
33383					e.preventDefault();
33384					_this.core.touchAction = 'zoomSwipe';
33385					endCoords = _this.getSwipeCords(e, Math.abs(_this.rotateValue));
33386					var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
33387					if (Math.abs(endCoords.x - startCoords.x) > 15 ||
33388						Math.abs(endCoords.y - startCoords.y) > 15) {
33389						isMoved = true;
33390						_this.setZoomSwipeStyles(_LGel, distance);
33391					}
33392				}
33393			});
33394			this.core.$inner.on('touchend.lg', function (e) {
33395				if (_this.core.touchAction === 'zoomSwipe' &&
33396					(_this.$LG(e.target).hasClass('lg-item') ||
33397						$item.get().contains(e.target))) {
33398					_this.core.touchAction = undefined;
33399					_this.core.outer.removeClass('lg-zoom-dragging');
33400					if (!isMoved) {
33401						return;
33402					}
33403					isMoved = false;
33404					endTime = new Date();
33405					var touchDuration = endTime.valueOf() - startTime.valueOf();
33406					_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration, _this.rotateValue);
33407				}
33408			});
33409		};
33410		Zoom.prototype.zoomDrag = function () {
33411			var _this = this;
33412			var startCoords = {};
33413			var endCoords = {};
33414			var isDragging = false;
33415			var isMoved = false;
33416			// Allow x direction drag
33417			var allowX = false;
33418			// Allow Y direction drag
33419			var allowY = false;
33420			var startTime;
33421			var endTime;
33422			var possibleSwipeCords;
33423			var _LGel;
33424			this.core.outer.on('mousedown.lg.zoom', function (e) {
33425				// Allow zoom only on image
33426				if (!_this.isImageSlide()) {
33427					return;
33428				}
33429				var $item = _this.core.getSlideItem(_this.core.index);
33430				if (_this.$LG(e.target).hasClass('lg-item') ||
33431					$item.get().contains(e.target)) {
33432					startTime = new Date();
33433					_LGel = _this.core
33434						.getSlideItem(_this.core.index)
33435						.find('.lg-img-wrap')
33436						.first();
33437					var dragAllowedAxises = _this.getDragAllowedAxises(Math.abs(_this.rotateValue));
33438					allowY = dragAllowedAxises.allowY;
33439					allowX = dragAllowedAxises.allowX;
33440					if (_this.core.outer.hasClass('lg-zoomed')) {
33441						if (_this.$LG(e.target).hasClass('lg-object') &&
33442							(allowX || allowY)) {
33443							e.preventDefault();
33444							startCoords = _this.getDragCords(e, Math.abs(_this.rotateValue));
33445							possibleSwipeCords = _this.getPossibleSwipeDragCords(_this.rotateValue);
33446							isDragging = true;
33447							// ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
33448							_this.core.outer.get().scrollLeft += 1;
33449							_this.core.outer.get().scrollLeft -= 1;
33450							_this.core.outer
33451								.removeClass('lg-grab')
33452								.addClass('lg-grabbing lg-zoom-drag-transition lg-zoom-dragging');
33453							// reset opacity and transition duration
33454						}
33455					}
33456				}
33457			});
33458			this.$LG(window).on("mousemove.lg.zoom.global" + this.core.lgId, function (e) {
33459				if (isDragging) {
33460					isMoved = true;
33461					endCoords = _this.getDragCords(e, Math.abs(_this.rotateValue));
33462					var distance = _this.getZoomSwipeCords(startCoords, endCoords, allowX, allowY, possibleSwipeCords);
33463					_this.setZoomSwipeStyles(_LGel, distance);
33464				}
33465			});
33466			this.$LG(window).on("mouseup.lg.zoom.global" + this.core.lgId, function (e) {
33467				if (isDragging) {
33468					endTime = new Date();
33469					isDragging = false;
33470					_this.core.outer.removeClass('lg-zoom-dragging');
33471					// Fix for chrome mouse move on click
33472					if (isMoved &&
33473						(startCoords.x !== endCoords.x ||
33474							startCoords.y !== endCoords.y)) {
33475						endCoords = _this.getDragCords(e, Math.abs(_this.rotateValue));
33476						var touchDuration = endTime.valueOf() - startTime.valueOf();
33477						_this.touchendZoom(startCoords, endCoords, allowX, allowY, touchDuration, _this.rotateValue);
33478					}
33479					isMoved = false;
33480				}
33481				_this.core.outer.removeClass('lg-grabbing').addClass('lg-grab');
33482			});
33483		};
33484		Zoom.prototype.closeGallery = function () {
33485			this.resetZoom();
33486		};
33487		Zoom.prototype.destroy = function () {
33488			// Unbind all events added by lightGallery zoom plugin
33489			this.$LG(window).off(".lg.zoom.global" + this.core.lgId);
33490			this.core.LGel.off('.lg.zoom');
33491			this.core.LGel.off('.zoom');
33492			clearTimeout(this.zoomableTimeout);
33493			this.zoomableTimeout = false;
33494		};
33495		return Zoom;
33496	}());
33497
33498	return Zoom;
33499
33500})));
33501/*!
33502 * lightgallery | 2.5.0 | June 13th 2022
33503 * http://www.lightgalleryjs.com/
33504 * Copyright (c) 2020 Sachin Neravath;
33505 * @license GPLv3
33506 */
33507
33508(function (global, factory) {
33509	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
33510	typeof define === 'function' && define.amd ? define(factory) :
33511	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgFullscreen = factory());
33512}(this, (function () { 'use strict';
33513
33514	/*! *****************************************************************************
33515	Copyright (c) Microsoft Corporation.
33516
33517	Permission to use, copy, modify, and/or distribute this software for any
33518	purpose with or without fee is hereby granted.
33519
33520	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
33521	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
33522	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
33523	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
33524	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
33525	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
33526	PERFORMANCE OF THIS SOFTWARE.
33527	***************************************************************************** */
33528
33529	var __assign = function() {
33530		__assign = Object.assign || function __assign(t) {
33531			for (var s, i = 1, n = arguments.length; i < n; i++) {
33532				s = arguments[i];
33533				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
33534			}
33535			return t;
33536		};
33537		return __assign.apply(this, arguments);
33538	};
33539
33540	var fullscreenSettings = {
33541		fullScreen: true,
33542		fullscreenPluginStrings: {
33543			toggleFullscreen: 'Toggle Fullscreen',
33544		},
33545	};
33546
33547	var FullScreen = /** @class */ (function () {
33548		function FullScreen(instance, $LG) {
33549			// get lightGallery core plugin instance
33550			this.core = instance;
33551			this.$LG = $LG;
33552			// extend module default settings with lightGallery core settings
33553			this.settings = __assign(__assign({}, fullscreenSettings), this.core.settings);
33554			return this;
33555		}
33556		FullScreen.prototype.init = function () {
33557			var fullScreen = '';
33558			if (this.settings.fullScreen) {
33559				// check for fullscreen browser support
33560				if (!document.fullscreenEnabled &&
33561					!document.webkitFullscreenEnabled &&
33562					!document.mozFullScreenEnabled &&
33563					!document.msFullscreenEnabled) {
33564					return;
33565				}
33566				else {
33567					fullScreen = "<button type=\"button\" aria-label=\"" + this.settings.fullscreenPluginStrings['toggleFullscreen'] + "\" class=\"lg-fullscreen lg-icon\"></button>";
33568					this.core.$toolbar.append(fullScreen);
33569					this.fullScreen();
33570				}
33571			}
33572		};
33573		FullScreen.prototype.isFullScreen = function () {
33574			return (document.fullscreenElement ||
33575				document.mozFullScreenElement ||
33576				document.webkitFullscreenElement ||
33577				document.msFullscreenElement);
33578		};
33579		FullScreen.prototype.requestFullscreen = function () {
33580			var el = document.documentElement;
33581			if (el.requestFullscreen) {
33582				el.requestFullscreen();
33583			}
33584			else if (el.msRequestFullscreen) {
33585				el.msRequestFullscreen();
33586			}
33587			else if (el.mozRequestFullScreen) {
33588				el.mozRequestFullScreen();
33589			}
33590			else if (el.webkitRequestFullscreen) {
33591				el.webkitRequestFullscreen();
33592			}
33593		};
33594		FullScreen.prototype.exitFullscreen = function () {
33595			if (document.exitFullscreen) {
33596				document.exitFullscreen();
33597			}
33598			else if (document.msExitFullscreen) {
33599				document.msExitFullscreen();
33600			}
33601			else if (document.mozCancelFullScreen) {
33602				document.mozCancelFullScreen();
33603			}
33604			else if (document.webkitExitFullscreen) {
33605				document.webkitExitFullscreen();
33606			}
33607		};
33608		// https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode
33609		FullScreen.prototype.fullScreen = function () {
33610			var _this = this;
33611			this.$LG(document).on("fullscreenchange.lg.global" + this.core.lgId + " \n            webkitfullscreenchange.lg.global" + this.core.lgId + " \n            mozfullscreenchange.lg.global" + this.core.lgId + " \n            MSFullscreenChange.lg.global" + this.core.lgId, function () {
33612				if (!_this.core.lgOpened)
33613					return;
33614				_this.core.outer.toggleClass('lg-fullscreen-on');
33615			});
33616			this.core.outer
33617				.find('.lg-fullscreen')
33618				.first()
33619				.on('click.lg', function () {
33620				if (_this.isFullScreen()) {
33621					_this.exitFullscreen();
33622				}
33623				else {
33624					_this.requestFullscreen();
33625				}
33626			});
33627		};
33628		FullScreen.prototype.closeGallery = function () {
33629			// exit from fullscreen if activated
33630			if (this.isFullScreen()) {
33631				this.exitFullscreen();
33632			}
33633		};
33634		FullScreen.prototype.destroy = function () {
33635			this.$LG(document).off("fullscreenchange.lg.global" + this.core.lgId + " \n            webkitfullscreenchange.lg.global" + this.core.lgId + " \n            mozfullscreenchange.lg.global" + this.core.lgId + " \n            MSFullscreenChange.lg.global" + this.core.lgId);
33636		};
33637		return FullScreen;
33638	}());
33639
33640	return FullScreen;
33641
33642})));
33643
33644/*!
33645 * lightgallery | 2.5.0 | June 13th 2022
33646 * http://www.lightgalleryjs.com/
33647 * Copyright (c) 2020 Sachin Neravath;
33648 * @license GPLv3
33649 */
33650
33651(function (global, factory) {
33652	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
33653	typeof define === 'function' && define.amd ? define(factory) :
33654	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgHash = factory());
33655}(this, (function () { 'use strict';
33656
33657	/*! *****************************************************************************
33658	Copyright (c) Microsoft Corporation.
33659
33660	Permission to use, copy, modify, and/or distribute this software for any
33661	purpose with or without fee is hereby granted.
33662
33663	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
33664	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
33665	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
33666	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
33667	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
33668	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
33669	PERFORMANCE OF THIS SOFTWARE.
33670	***************************************************************************** */
33671
33672	var __assign = function() {
33673		__assign = Object.assign || function __assign(t) {
33674			for (var s, i = 1, n = arguments.length; i < n; i++) {
33675				s = arguments[i];
33676				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
33677			}
33678			return t;
33679		};
33680		return __assign.apply(this, arguments);
33681	};
33682
33683	/**
33684	 * List of lightGallery events
33685	 * All events should be documented here
33686	 * Below interfaces are used to build the website documentations
33687	 * */
33688	var lGEvents = {
33689		afterAppendSlide: 'lgAfterAppendSlide',
33690		init: 'lgInit',
33691		hasVideo: 'lgHasVideo',
33692		containerResize: 'lgContainerResize',
33693		updateSlides: 'lgUpdateSlides',
33694		afterAppendSubHtml: 'lgAfterAppendSubHtml',
33695		beforeOpen: 'lgBeforeOpen',
33696		afterOpen: 'lgAfterOpen',
33697		slideItemLoad: 'lgSlideItemLoad',
33698		beforeSlide: 'lgBeforeSlide',
33699		afterSlide: 'lgAfterSlide',
33700		posterClick: 'lgPosterClick',
33701		dragStart: 'lgDragStart',
33702		dragMove: 'lgDragMove',
33703		dragEnd: 'lgDragEnd',
33704		beforeNextSlide: 'lgBeforeNextSlide',
33705		beforePrevSlide: 'lgBeforePrevSlide',
33706		beforeClose: 'lgBeforeClose',
33707		afterClose: 'lgAfterClose',
33708		rotateLeft: 'lgRotateLeft',
33709		rotateRight: 'lgRotateRight',
33710		flipHorizontal: 'lgFlipHorizontal',
33711		flipVertical: 'lgFlipVertical',
33712		autoplay: 'lgAutoplay',
33713		autoplayStart: 'lgAutoplayStart',
33714		autoplayStop: 'lgAutoplayStop',
33715	};
33716
33717	var hashSettings = {
33718		hash: true,
33719		galleryId: '1',
33720		customSlideName: false,
33721	};
33722
33723	var Hash = /** @class */ (function () {
33724		function Hash(instance, $LG) {
33725			// get lightGallery core plugin instance
33726			this.core = instance;
33727			this.$LG = $LG;
33728			// extend module default settings with lightGallery core settings
33729			this.settings = __assign(__assign({}, hashSettings), this.core.settings);
33730			return this;
33731		}
33732		Hash.prototype.init = function () {
33733			var _this = this;
33734			if (!this.settings.hash) {
33735				return;
33736			}
33737			this.oldHash = window.location.hash;
33738			setTimeout(function () {
33739				_this.buildFromHash();
33740			}, 100);
33741			// Change hash value on after each slide transition
33742			this.core.LGel.on(lGEvents.afterSlide + ".hash", this.onAfterSlide.bind(this));
33743			this.core.LGel.on(lGEvents.afterClose + ".hash", this.onCloseAfter.bind(this));
33744			// Listen hash change and change the slide according to slide value
33745			this.$LG(window).on("hashchange.lg.hash.global" + this.core.lgId, this.onHashchange.bind(this));
33746		};
33747		Hash.prototype.onAfterSlide = function (event) {
33748			var slideName = this.core.galleryItems[event.detail.index].slideName;
33749			slideName = this.settings.customSlideName
33750				? slideName || event.detail.index
33751				: event.detail.index;
33752			if (history.replaceState) {
33753				history.replaceState(null, '', window.location.pathname +
33754					window.location.search +
33755					'#lg=' +
33756					this.settings.galleryId +
33757					'&slide=' +
33758					slideName);
33759			}
33760			else {
33761				window.location.hash =
33762					'lg=' + this.settings.galleryId + '&slide=' + slideName;
33763			}
33764		};
33765		/**
33766		 * Get index of the slide from custom slideName. Has to be a public method. Used in hash plugin
33767		 * @param {String} hash
33768		 * @returns {Number} Index of the slide.
33769		 */
33770		Hash.prototype.getIndexFromUrl = function (hash) {
33771			if (hash === void 0) { hash = window.location.hash; }
33772			var slideName = hash.split('&slide=')[1];
33773			var _idx = 0;
33774			if (this.settings.customSlideName) {
33775				for (var index = 0; index < this.core.galleryItems.length; index++) {
33776					var dynamicEl = this.core.galleryItems[index];
33777					if (dynamicEl.slideName === slideName) {
33778						_idx = index;
33779						break;
33780					}
33781				}
33782			}
33783			else {
33784				_idx = parseInt(slideName, 10);
33785			}
33786			return isNaN(_idx) ? 0 : _idx;
33787		};
33788		// Build Gallery if gallery id exist in the URL
33789		Hash.prototype.buildFromHash = function () {
33790			// if dynamic option is enabled execute immediately
33791			var _hash = window.location.hash;
33792			//Uncode edit ##START##
33793			// if (_hash.indexOf('lg=' + this.settings.galleryId) > 0) {
33794			if (_hash.indexOf('lg=' + this.settings.galleryId + '&') > 0) {
33795			//Uncode edit ##END##
33796				// This class is used to remove the initial animation if galleryId present in the URL
33797				this.$LG(document.body).addClass('lg-from-hash');
33798				var index = this.getIndexFromUrl(_hash);
33799				this.core.openGallery(index);
33800				return true;
33801			}
33802		};
33803		Hash.prototype.onCloseAfter = function () {
33804			// Reset to old hash value
33805			if (this.oldHash &&
33806				this.oldHash.indexOf('lg=' + this.settings.galleryId) < 0) {
33807				if (history.replaceState) {
33808					history.replaceState(null, '', this.oldHash);
33809				}
33810				else {
33811					window.location.hash = this.oldHash;
33812				}
33813			}
33814			else {
33815				if (history.replaceState) {
33816					history.replaceState(null, document.title, window.location.pathname + window.location.search);
33817				}
33818				else {
33819					window.location.hash = '';
33820				}
33821			}
33822		};
33823		Hash.prototype.onHashchange = function () {
33824			if (!this.core.lgOpened)
33825				return;
33826			var _hash = window.location.hash;
33827			var index = this.getIndexFromUrl(_hash);
33828			// it galleryId doesn't exist in the url close the gallery
33829			if (_hash.indexOf('lg=' + this.settings.galleryId) > -1) {
33830				this.core.slide(index, false, false);
33831			}
33832			else if (this.core.lGalleryOn) {
33833				this.core.closeGallery();
33834			}
33835		};
33836		Hash.prototype.closeGallery = function () {
33837			if (this.settings.hash) {
33838				this.$LG(document.body).removeClass('lg-from-hash');
33839			}
33840		};
33841		Hash.prototype.destroy = function () {
33842			this.core.LGel.off('.lg.hash');
33843			this.core.LGel.off('.hash');
33844			this.$LG(window).off("hashchange.lg.hash.global" + this.core.lgId);
33845		};
33846		return Hash;
33847	}());
33848
33849	return Hash;
33850
33851})));
33852/*!
33853 * lightgallery | 2.5.0 | June 13th 2022
33854 * http://www.lightgalleryjs.com/
33855 * Copyright (c) 2020 Sachin Neravath;
33856 * @license GPLv3
33857 */
33858
33859(function (global, factory) {
33860	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
33861	typeof define === 'function' && define.amd ? define(factory) :
33862	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgShare = factory());
33863}(this, (function () { 'use strict';
33864
33865	/*! *****************************************************************************
33866	Copyright (c) Microsoft Corporation.
33867
33868	Permission to use, copy, modify, and/or distribute this software for any
33869	purpose with or without fee is hereby granted.
33870
33871	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
33872	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
33873	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
33874	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
33875	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
33876	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
33877	PERFORMANCE OF THIS SOFTWARE.
33878	***************************************************************************** */
33879
33880	var __assign = function() {
33881		__assign = Object.assign || function __assign(t) {
33882			for (var s, i = 1, n = arguments.length; i < n; i++) {
33883				s = arguments[i];
33884				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
33885			}
33886			return t;
33887		};
33888		return __assign.apply(this, arguments);
33889	};
33890
33891	function __spreadArrays() {
33892		for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
33893		for (var r = Array(s), k = 0, i = 0; i < il; i++)
33894			for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
33895				r[k] = a[j];
33896		return r;
33897	}
33898
33899	var shareSettings = {
33900		share: true,
33901		facebook: true,
33902		facebookDropdownText: 'Facebook',
33903		twitter: true,
33904		twitterDropdownText: 'Twitter',
33905		pinterest: true,
33906		pinterestDropdownText: 'Pinterest',
33907		additionalShareOptions: [],
33908		sharePluginStrings: { share: 'Share' },
33909	};
33910
33911	function getFacebookShareLink(galleryItem) {
33912		var facebookBaseUrl = '//www.facebook.com/sharer/sharer.php?u=';
33913		return (facebookBaseUrl +
33914			encodeURIComponent(galleryItem.facebookShareUrl || window.location.href));
33915	}
33916
33917	function getTwitterShareLink(galleryItem) {
33918		var twitterBaseUrl = '//twitter.com/intent/tweet?text=';
33919		var url = encodeURIComponent(galleryItem.twitterShareUrl || window.location.href);
33920		var text = galleryItem.tweetText;
33921		return twitterBaseUrl + text + '&url=' + url;
33922	}
33923
33924	function getPinterestShareLink(galleryItem) {
33925		var pinterestBaseUrl = 'http://www.pinterest.com/pin/create/button/?url=';
33926		var description = galleryItem.pinterestText;
33927		var media = encodeURIComponent(galleryItem.src);
33928		var url = encodeURIComponent(galleryItem.pinterestShareUrl || window.location.href);
33929		return (pinterestBaseUrl +
33930			url +
33931			'&media=' +
33932			media +
33933			'&description=' +
33934			description);
33935	}
33936
33937	/**
33938	 * List of lightGallery events
33939	 * All events should be documented here
33940	 * Below interfaces are used to build the website documentations
33941	 * */
33942	var lGEvents = {
33943		afterAppendSlide: 'lgAfterAppendSlide',
33944		init: 'lgInit',
33945		hasVideo: 'lgHasVideo',
33946		containerResize: 'lgContainerResize',
33947		updateSlides: 'lgUpdateSlides',
33948		afterAppendSubHtml: 'lgAfterAppendSubHtml',
33949		beforeOpen: 'lgBeforeOpen',
33950		afterOpen: 'lgAfterOpen',
33951		slideItemLoad: 'lgSlideItemLoad',
33952		beforeSlide: 'lgBeforeSlide',
33953		afterSlide: 'lgAfterSlide',
33954		posterClick: 'lgPosterClick',
33955		dragStart: 'lgDragStart',
33956		dragMove: 'lgDragMove',
33957		dragEnd: 'lgDragEnd',
33958		beforeNextSlide: 'lgBeforeNextSlide',
33959		beforePrevSlide: 'lgBeforePrevSlide',
33960		beforeClose: 'lgBeforeClose',
33961		afterClose: 'lgAfterClose',
33962		rotateLeft: 'lgRotateLeft',
33963		rotateRight: 'lgRotateRight',
33964		flipHorizontal: 'lgFlipHorizontal',
33965		flipVertical: 'lgFlipVertical',
33966		autoplay: 'lgAutoplay',
33967		autoplayStart: 'lgAutoplayStart',
33968		autoplayStop: 'lgAutoplayStop',
33969	};
33970
33971	var Share = /** @class */ (function () {
33972		function Share(instance) {
33973			this.shareOptions = [];
33974			// get lightGallery core plugin instance
33975			this.core = instance;
33976			// extend module default settings with lightGallery core settings
33977			this.settings = __assign(__assign({}, shareSettings), this.core.settings);
33978			return this;
33979		}
33980		Share.prototype.init = function () {
33981			if (!this.settings.share) {
33982				return;
33983			}
33984			this.shareOptions = __spreadArrays(this.getDefaultShareOptions(), this.settings.additionalShareOptions);
33985			this.setLgShareMarkup();
33986			this.core.outer
33987				.find('.lg-share .lg-dropdown')
33988				.append(this.getShareListHtml());
33989			this.core.LGel.on(lGEvents.afterSlide + ".share", this.onAfterSlide.bind(this));
33990		};
33991		Share.prototype.getShareListHtml = function () {
33992			var shareHtml = '';
33993			this.shareOptions.forEach(function (shareOption) {
33994				shareHtml += shareOption.dropdownHTML;
33995			});
33996			return shareHtml;
33997		};
33998		Share.prototype.setLgShareMarkup = function () {
33999			var _this = this;
34000			this.core.$toolbar.append("<button type=\"button\" aria-label=\"" + this.settings.sharePluginStrings['share'] + "\" aria-haspopup=\"true\" aria-expanded=\"false\" class=\"lg-share lg-icon\">\n                <ul class=\"lg-dropdown\" style=\"position: absolute;\"></ul></button>");
34001			this.core.outer.append('<div class="lg-dropdown-overlay"></div>');
34002			var $shareButton = this.core.outer.find('.lg-share');
34003			$shareButton.first().on('click.lg', function () {
34004				_this.core.outer.toggleClass('lg-dropdown-active');
34005				if (_this.core.outer.hasClass('lg-dropdown-active')) {
34006					_this.core.outer.attr('aria-expanded', true);
34007				}
34008				else {
34009					_this.core.outer.attr('aria-expanded', false);
34010				}
34011			});
34012			this.core.outer
34013				.find('.lg-dropdown-overlay')
34014				.first()
34015				.on('click.lg', function () {
34016				_this.core.outer.removeClass('lg-dropdown-active');
34017				_this.core.outer.attr('aria-expanded', false);
34018			});
34019		};
34020		Share.prototype.onAfterSlide = function (event) {
34021			var _this = this;
34022			var index = event.detail.index;
34023			var currentItem = this.core.galleryItems[index];
34024			setTimeout(function () {
34025				_this.shareOptions.forEach(function (shareOption) {
34026					var selector = shareOption.selector;
34027					_this.core.outer
34028						.find(selector)
34029						.attr('href', shareOption.generateLink(currentItem));
34030				});
34031			}, 100);
34032		};
34033		Share.prototype.getShareListItemHTML = function (type, text) {
34034			return "<li><a class=\"lg-share-" + type + "\" rel=\"noopener\" target=\"_blank\"><span class=\"lg-icon\"></span><span class=\"lg-dropdown-text\">" + text + "</span></a></li>";
34035		};
34036		Share.prototype.getDefaultShareOptions = function () {
34037			return __spreadArrays((this.settings.facebook
34038				? [
34039					{
34040						type: 'facebook',
34041						generateLink: getFacebookShareLink,
34042						dropdownHTML: this.getShareListItemHTML('facebook', this.settings.facebookDropdownText),
34043						selector: '.lg-share-facebook',
34044					},
34045				]
34046				: []), (this.settings.twitter
34047				? [
34048					{
34049						type: 'twitter',
34050						generateLink: getTwitterShareLink,
34051						dropdownHTML: this.getShareListItemHTML('twitter', this.settings.twitterDropdownText),
34052						selector: '.lg-share-twitter',
34053					},
34054				]
34055				: []), (this.settings.pinterest
34056				? [
34057					{
34058						type: 'pinterest',
34059						generateLink: getPinterestShareLink,
34060						dropdownHTML: this.getShareListItemHTML('pinterest', this.settings.pinterestDropdownText),
34061						selector: '.lg-share-pinterest',
34062					},
34063				]
34064				: []));
34065		};
34066		Share.prototype.destroy = function () {
34067			this.core.outer.find('.lg-dropdown-overlay').remove();
34068			this.core.outer.find('.lg-share').remove();
34069			this.core.LGel.off('.lg.share');
34070			this.core.LGel.off('.share');
34071		};
34072		return Share;
34073	}());
34074
34075	return Share;
34076
34077})));
34078/*!
34079 * lightgallery | 2.5.0 | June 13th 2022
34080 * http://www.lightgalleryjs.com/
34081 * Copyright (c) 2020 Sachin Neravath;
34082 * @license GPLv3
34083 */
34084
34085(function (global, factory) {
34086	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
34087	typeof define === 'function' && define.amd ? define(factory) :
34088	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgThumbnail = factory());
34089}(this, (function () { 'use strict';
34090
34091	/*! *****************************************************************************
34092	Copyright (c) Microsoft Corporation.
34093
34094	Permission to use, copy, modify, and/or distribute this software for any
34095	purpose with or without fee is hereby granted.
34096
34097	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
34098	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
34099	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
34100	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
34101	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
34102	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
34103	PERFORMANCE OF THIS SOFTWARE.
34104	***************************************************************************** */
34105
34106	var __assign = function() {
34107		__assign = Object.assign || function __assign(t) {
34108			for (var s, i = 1, n = arguments.length; i < n; i++) {
34109				s = arguments[i];
34110				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
34111			}
34112			return t;
34113		};
34114		return __assign.apply(this, arguments);
34115	};
34116
34117	var thumbnailsSettings = {
34118		thumbnail: true,
34119		animateThumb: true,
34120		currentPagerPosition: 'middle',
34121		alignThumbnails: 'middle',
34122		thumbWidth: 100,
34123		thumbHeight: '80px',
34124		thumbMargin: 5,
34125		appendThumbnailsTo: '.lg-components',
34126		toggleThumb: false,
34127		enableThumbDrag: true,
34128		enableThumbSwipe: true,
34129		thumbnailSwipeThreshold: 10,
34130		loadYouTubeThumbnail: true,
34131		youTubeThumbSize: 1,
34132		thumbnailPluginStrings: {
34133			toggleThumbnails: 'Toggle thumbnails',
34134		},
34135	};
34136
34137	/**
34138	 * List of lightGallery events
34139	 * All events should be documented here
34140	 * Below interfaces are used to build the website documentations
34141	 * */
34142	var lGEvents = {
34143		afterAppendSlide: 'lgAfterAppendSlide',
34144		init: 'lgInit',
34145		hasVideo: 'lgHasVideo',
34146		containerResize: 'lgContainerResize',
34147		updateSlides: 'lgUpdateSlides',
34148		afterAppendSubHtml: 'lgAfterAppendSubHtml',
34149		beforeOpen: 'lgBeforeOpen',
34150		afterOpen: 'lgAfterOpen',
34151		slideItemLoad: 'lgSlideItemLoad',
34152		beforeSlide: 'lgBeforeSlide',
34153		afterSlide: 'lgAfterSlide',
34154		posterClick: 'lgPosterClick',
34155		dragStart: 'lgDragStart',
34156		dragMove: 'lgDragMove',
34157		dragEnd: 'lgDragEnd',
34158		beforeNextSlide: 'lgBeforeNextSlide',
34159		beforePrevSlide: 'lgBeforePrevSlide',
34160		beforeClose: 'lgBeforeClose',
34161		afterClose: 'lgAfterClose',
34162		rotateLeft: 'lgRotateLeft',
34163		rotateRight: 'lgRotateRight',
34164		flipHorizontal: 'lgFlipHorizontal',
34165		flipVertical: 'lgFlipVertical',
34166		autoplay: 'lgAutoplay',
34167		autoplayStart: 'lgAutoplayStart',
34168		autoplayStop: 'lgAutoplayStop',
34169	};
34170
34171	var Thumbnail = /** @class */ (function () {
34172		function Thumbnail(instance, $LG) {
34173			this.thumbOuterWidth = 0;
34174			this.thumbTotalWidth = 0;
34175			this.translateX = 0;
34176			this.thumbClickable = false;
34177			// get lightGallery core plugin instance
34178			this.core = instance;
34179			this.$LG = $LG;
34180			return this;
34181		}
34182		Thumbnail.prototype.init = function () {
34183			// extend module default settings with lightGallery core settings
34184			this.settings = __assign(__assign({}, thumbnailsSettings), this.core.settings);
34185			this.thumbOuterWidth = 0;
34186			this.thumbTotalWidth =
34187				this.core.galleryItems.length *
34188					(this.settings.thumbWidth + this.settings.thumbMargin);
34189			// Thumbnail animation value
34190			this.translateX = 0;
34191			this.setAnimateThumbStyles();
34192			if (!this.core.settings.allowMediaOverlap) {
34193				this.settings.toggleThumb = false;
34194			}
34195			if (this.settings.thumbnail) {
34196				this.build();
34197				if (this.settings.animateThumb) {
34198					if (this.settings.enableThumbDrag) {
34199						this.enableThumbDrag();
34200					}
34201					if (this.settings.enableThumbSwipe) {
34202						this.enableThumbSwipe();
34203					}
34204					this.thumbClickable = false;
34205				}
34206				else {
34207					this.thumbClickable = true;
34208				}
34209				this.toggleThumbBar();
34210				this.thumbKeyPress();
34211			}
34212		};
34213		Thumbnail.prototype.build = function () {
34214			var _this = this;
34215			this.setThumbMarkup();
34216			this.manageActiveClassOnSlideChange();
34217			this.$lgThumb.first().on('click.lg touchend.lg', function (e) {
34218				var $target = _this.$LG(e.target);
34219				if (!$target.hasAttribute('data-lg-item-id')) {
34220					return;
34221				}
34222				setTimeout(function () {
34223					// In IE9 and bellow touch does not support
34224					// Go to slide if browser does not support css transitions
34225					if (_this.thumbClickable && !_this.core.lgBusy) {
34226						var index = parseInt($target.attr('data-lg-item-id'));
34227						_this.core.slide(index, false, true, false);
34228					}
34229				}, 50);
34230			});
34231			//Uncode edit ##START##
34232			// this.core.LGel.on(lGEvents.beforeSlide + ".thumb", function (event) {
34233			this.core.LGel.on(lGEvents.beforeSlide, function (event) {
34234			//Uncode edit ##END##
34235				var index = event.detail.index;
34236				_this.animateThumb(index);
34237			});
34238			//Uncode edit ##START##
34239			// this.core.LGel.on(lGEvents.beforeOpen + ".thumb", function () {
34240			this.core.LGel.on(lGEvents.beforeOpen, function () {
34241			//Uncode edit ##END##
34242				_this.thumbOuterWidth = _this.core.outer.get().offsetWidth;
34243			});
34244			//Uncode edit ##START##
34245			// this.core.LGel.on(lGEvents.updateSlides + ".thumb", function () {
34246			this.core.LGel.on(lGEvents.updateSlides, function () {
34247			//Uncode edit ##END##
34248				_this.rebuildThumbnails();
34249			});
34250			//Uncode edit ##START##
34251			// this.core.LGel.on(lGEvents.containerResize + ".thumb", function () {
34252			this.core.LGel.on(lGEvents.containerResize, function () {
34253			//Uncode edit ##END##
34254				if (!_this.core.lgOpened)
34255					return;
34256				setTimeout(function () {
34257					_this.thumbOuterWidth = _this.core.outer.get().offsetWidth;
34258					_this.animateThumb(_this.core.index);
34259					_this.thumbOuterWidth = _this.core.outer.get().offsetWidth;
34260				}, 50);
34261			});
34262		};
34263		Thumbnail.prototype.setThumbMarkup = function () {
34264			var thumbOuterClassNames = 'lg-thumb-outer ';
34265			if (this.settings.alignThumbnails) {
34266				thumbOuterClassNames += "lg-thumb-align-" + this.settings.alignThumbnails;
34267			}
34268			var html = "<div class=\"" + thumbOuterClassNames + "\">\n        <div class=\"lg-thumb lg-group\">\n        </div>\n        </div>";
34269			this.core.outer.addClass('lg-has-thumb');
34270			if (this.settings.appendThumbnailsTo === '.lg-components') {
34271				this.core.$lgComponents.append(html);
34272			}
34273			else {
34274				this.core.outer.append(html);
34275			}
34276			this.$thumbOuter = this.core.outer.find('.lg-thumb-outer').first();
34277			this.$lgThumb = this.core.outer.find('.lg-thumb').first();
34278			if (this.settings.animateThumb) {
34279				this.core.outer
34280					.find('.lg-thumb')
34281					.css('transition-duration', this.core.settings.speed + 'ms')
34282					.css('width', this.thumbTotalWidth + 'px')
34283					.css('position', 'relative');
34284			}
34285			this.setThumbItemHtml(this.core.galleryItems);
34286		};
34287		Thumbnail.prototype.enableThumbDrag = function () {
34288			var _this = this;
34289			var thumbDragUtils = {
34290				cords: {
34291					startX: 0,
34292					endX: 0,
34293				},
34294				isMoved: false,
34295				newTranslateX: 0,
34296				startTime: new Date(),
34297				endTime: new Date(),
34298				touchMoveTime: 0,
34299			};
34300			var isDragging = false;
34301			this.$thumbOuter.addClass('lg-grab');
34302			this.core.outer
34303				.find('.lg-thumb')
34304				.first()
34305				.on('mousedown.lg.thumb', function (e) {
34306				if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
34307					// execute only on .lg-object
34308					e.preventDefault();
34309					thumbDragUtils.cords.startX = e.pageX;
34310					thumbDragUtils.startTime = new Date();
34311					_this.thumbClickable = false;
34312					isDragging = true;
34313					// ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
34314					_this.core.outer.get().scrollLeft += 1;
34315					_this.core.outer.get().scrollLeft -= 1;
34316					// *
34317					_this.$thumbOuter
34318						.removeClass('lg-grab')
34319						.addClass('lg-grabbing');
34320				}
34321			});
34322			this.$LG(window).on("mousemove.lg.thumb.global" + this.core.lgId, function (e) {
34323				if (!_this.core.lgOpened)
34324					return;
34325				if (isDragging) {
34326					thumbDragUtils.cords.endX = e.pageX;
34327					thumbDragUtils = _this.onThumbTouchMove(thumbDragUtils);
34328				}
34329			});
34330			this.$LG(window).on("mouseup.lg.thumb.global" + this.core.lgId, function () {
34331				if (!_this.core.lgOpened)
34332					return;
34333				if (thumbDragUtils.isMoved) {
34334					thumbDragUtils = _this.onThumbTouchEnd(thumbDragUtils);
34335				}
34336				else {
34337					_this.thumbClickable = true;
34338				}
34339				if (isDragging) {
34340					isDragging = false;
34341					_this.$thumbOuter.removeClass('lg-grabbing').addClass('lg-grab');
34342				}
34343			});
34344		};
34345		Thumbnail.prototype.enableThumbSwipe = function () {
34346			var _this = this;
34347			var thumbDragUtils = {
34348				cords: {
34349					startX: 0,
34350					endX: 0,
34351				},
34352				isMoved: false,
34353				newTranslateX: 0,
34354				startTime: new Date(),
34355				endTime: new Date(),
34356				touchMoveTime: 0,
34357			};
34358			this.$lgThumb.on('touchstart.lg', function (e) {
34359				if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
34360					e.preventDefault();
34361					thumbDragUtils.cords.startX = e.targetTouches[0].pageX;
34362					_this.thumbClickable = false;
34363					thumbDragUtils.startTime = new Date();
34364				}
34365			});
34366			this.$lgThumb.on('touchmove.lg', function (e) {
34367				if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
34368					e.preventDefault();
34369					thumbDragUtils.cords.endX = e.targetTouches[0].pageX;
34370					thumbDragUtils = _this.onThumbTouchMove(thumbDragUtils);
34371				}
34372			});
34373			this.$lgThumb.on('touchend.lg', function () {
34374				if (thumbDragUtils.isMoved) {
34375					thumbDragUtils = _this.onThumbTouchEnd(thumbDragUtils);
34376				}
34377				else {
34378					_this.thumbClickable = true;
34379				}
34380			});
34381		};
34382		// Rebuild thumbnails
34383		Thumbnail.prototype.rebuildThumbnails = function () {
34384			var _this = this;
34385			// Remove transitions
34386			this.$thumbOuter.addClass('lg-rebuilding-thumbnails');
34387			setTimeout(function () {
34388				_this.thumbTotalWidth =
34389					_this.core.galleryItems.length *
34390						(_this.settings.thumbWidth + _this.settings.thumbMargin);
34391				_this.$lgThumb.css('width', _this.thumbTotalWidth + 'px');
34392				_this.$lgThumb.empty();
34393				_this.setThumbItemHtml(_this.core.galleryItems);
34394				_this.animateThumb(_this.core.index);
34395			}, 50);
34396			setTimeout(function () {
34397				_this.$thumbOuter.removeClass('lg-rebuilding-thumbnails');
34398			}, 200);
34399		};
34400		// @ts-check
34401		Thumbnail.prototype.setTranslate = function (value) {
34402			this.$lgThumb.css('transform', 'translate3d(-' + value + 'px, 0px, 0px)');
34403		};
34404		Thumbnail.prototype.getPossibleTransformX = function (left) {
34405			if (left > this.thumbTotalWidth - this.thumbOuterWidth) {
34406				left = this.thumbTotalWidth - this.thumbOuterWidth;
34407			}
34408			if (left < 0) {
34409				left = 0;
34410			}
34411			return left;
34412		};
34413		Thumbnail.prototype.animateThumb = function (index) {
34414			this.$lgThumb.css('transition-duration', this.core.settings.speed + 'ms');
34415			if (this.settings.animateThumb) {
34416				var position = 0;
34417				switch (this.settings.currentPagerPosition) {
34418					case 'left':
34419						position = 0;
34420						break;
34421					case 'middle':
34422						position =
34423							this.thumbOuterWidth / 2 - this.settings.thumbWidth / 2;
34424						break;
34425					case 'right':
34426						position = this.thumbOuterWidth - this.settings.thumbWidth;
34427				}
34428				this.translateX =
34429					(this.settings.thumbWidth + this.settings.thumbMargin) * index -
34430						1 -
34431						position;
34432				if (this.translateX > this.thumbTotalWidth - this.thumbOuterWidth) {
34433					this.translateX = this.thumbTotalWidth - this.thumbOuterWidth;
34434				}
34435				if (this.translateX < 0) {
34436					this.translateX = 0;
34437				}
34438				this.setTranslate(this.translateX);
34439			}
34440		};
34441		Thumbnail.prototype.onThumbTouchMove = function (thumbDragUtils) {
34442			thumbDragUtils.newTranslateX = this.translateX;
34443			thumbDragUtils.isMoved = true;
34444			thumbDragUtils.touchMoveTime = new Date().valueOf();
34445			thumbDragUtils.newTranslateX -=
34446				thumbDragUtils.cords.endX - thumbDragUtils.cords.startX;
34447			thumbDragUtils.newTranslateX = this.getPossibleTransformX(thumbDragUtils.newTranslateX);
34448			// move current slide
34449			this.setTranslate(thumbDragUtils.newTranslateX);
34450			this.$thumbOuter.addClass('lg-dragging');
34451			return thumbDragUtils;
34452		};
34453		Thumbnail.prototype.onThumbTouchEnd = function (thumbDragUtils) {
34454			thumbDragUtils.isMoved = false;
34455			thumbDragUtils.endTime = new Date();
34456			this.$thumbOuter.removeClass('lg-dragging');
34457			var touchDuration = thumbDragUtils.endTime.valueOf() -
34458				thumbDragUtils.startTime.valueOf();
34459			var distanceXnew = thumbDragUtils.cords.endX - thumbDragUtils.cords.startX;
34460			var speedX = Math.abs(distanceXnew) / touchDuration;
34461			// Some magical numbers
34462			// Can be improved
34463			if (speedX > 0.15 &&
34464				thumbDragUtils.endTime.valueOf() - thumbDragUtils.touchMoveTime < 30) {
34465				speedX += 1;
34466				if (speedX > 2) {
34467					speedX += 1;
34468				}
34469				speedX =
34470					speedX +
34471						speedX * (Math.abs(distanceXnew) / this.thumbOuterWidth);
34472				this.$lgThumb.css('transition-duration', Math.min(speedX - 1, 2) + 'settings');
34473				distanceXnew = distanceXnew * speedX;
34474				this.translateX = this.getPossibleTransformX(this.translateX - distanceXnew);
34475				this.setTranslate(this.translateX);
34476			}
34477			else {
34478				this.translateX = thumbDragUtils.newTranslateX;
34479			}
34480			if (Math.abs(thumbDragUtils.cords.endX - thumbDragUtils.cords.startX) <
34481				this.settings.thumbnailSwipeThreshold) {
34482				this.thumbClickable = true;
34483			}
34484			return thumbDragUtils;
34485		};
34486		Thumbnail.prototype.getThumbHtml = function (thumb, index, alt) {
34487			var slideVideoInfo = this.core.galleryItems[index].__slideVideoInfo || {};
34488			var thumbImg,
34489				altTh = this.core.galleryItems[index].subHtml,
34490				altApp = '';
34491			if (slideVideoInfo.youtube) {
34492				if (this.settings.loadYouTubeThumbnail) {
34493					thumbImg =
34494						'//img.youtube.com/vi/' +
34495							slideVideoInfo.youtube[1] +
34496							'/' +
34497							this.settings.youTubeThumbSize +
34498							'.jpg';
34499				}
34500				else {
34501					thumbImg = thumb;
34502				}
34503			}
34504			else {
34505				thumbImg = thumb;
34506			}
34507
34508			if ( altTh ) {
34509				altTh = altTh.replace(/<\/?[^>]+(>|$)/g, "");
34510				altApp = 'alt=\"' + altTh + ' \" ';
34511			} else if ( typeof alt !== 'undefined' ) {
34512				altApp = 'alt=\"' + alt + ' \" ';
34513			}
34514
34515			if ( thumbImg ) {
34516				return "<div data-lg-item-id=\"" + index + "\" class=\"lg-thumb-item " + (index === this.core.index ? ' active' : '') + "\" \n        style=\"width:" + this.settings.thumbWidth + "px; height: " + this.settings.thumbHeight + ";\n            margin-right: " + this.settings.thumbMargin + "px;\">\n            <img data-lg-item-id=\"" + index + "\" " + altApp + "src=\"" + thumbImg + "\" />\n        </div>";
34517			} else {
34518				return "<div data-lg-item-id=\"" + index + "\" class=\"lg-thumb-item " + (index === this.core.index ? ' active' : '') + "\" \n        style=\"width:" + this.settings.thumbWidth + "px; height: " + this.settings.thumbHeight + ";\n            margin-right: " + this.settings.thumbMargin + "px;\">\n        </div>";
34519			}
34520		};
34521		Thumbnail.prototype.getThumbItemHtml = function (items) {
34522			var thumbList = '';
34523			for (var i = 0; i < items.length; i++) {
34524				thumbList += this.getThumbHtml(items[i].thumb, i, items[i].alt);
34525			}
34526			return thumbList;
34527		};
34528		Thumbnail.prototype.setThumbItemHtml = function (items) {
34529			var thumbList = this.getThumbItemHtml(items);
34530			this.$lgThumb.html(thumbList);
34531		};
34532		Thumbnail.prototype.setAnimateThumbStyles = function () {
34533			if (this.settings.animateThumb) {
34534				this.core.outer.addClass('lg-animate-thumb');
34535			}
34536		};
34537		// Manage thumbnail active calss
34538		Thumbnail.prototype.manageActiveClassOnSlideChange = function () {
34539			var _this = this;
34540			// manage active class for thumbnail
34541			//Uncode edit ##START##
34542			// this.core.LGel.on(lGEvents.beforeSlide + ".thumb", function (event) {
34543			this.core.LGel.on(lGEvents.beforeSlide, function (event) {
34544			//Uncode edit ##END##
34545				var $thumb = _this.core.outer.find('.lg-thumb-item');
34546				var index = event.detail.index;
34547				$thumb.removeClass('active');
34548				$thumb.eq(index).addClass('active');
34549			});
34550		};
34551		// Toggle thumbnail bar
34552		Thumbnail.prototype.toggleThumbBar = function () {
34553			var _this = this;
34554			if (this.settings.toggleThumb) {
34555				this.core.outer.addClass('lg-can-toggle');
34556				this.core.$toolbar.append('<button type="button" aria-label="' +
34557					this.settings.thumbnailPluginStrings['toggleThumbnails'] +
34558					'" class="lg-toggle-thumb lg-icon"></button>');
34559				this.core.outer
34560					.find('.lg-toggle-thumb')
34561					.first()
34562					.on('click.lg', function () {
34563					_this.core.outer.toggleClass('lg-components-open');
34564				});
34565			}
34566		};
34567		Thumbnail.prototype.thumbKeyPress = function () {
34568			var _this = this;
34569			this.$LG(window).on("keydown.lg.thumb.global" + this.core.lgId, function (e) {
34570				if (!_this.core.lgOpened || !_this.settings.toggleThumb)
34571					return;
34572				if (e.keyCode === 38) {
34573					e.preventDefault();
34574					_this.core.outer.addClass('lg-components-open');
34575				}
34576				else if (e.keyCode === 40) {
34577					e.preventDefault();
34578					_this.core.outer.removeClass('lg-components-open');
34579				}
34580			});
34581		};
34582		Thumbnail.prototype.destroy = function () {
34583			if (this.settings.thumbnail) {
34584				this.$LG(window).off(".lg.thumb.global" + this.core.lgId);
34585				this.core.LGel.off('.lg.thumb');
34586				this.core.LGel.off('.thumb');
34587				this.$thumbOuter.remove();
34588				this.core.outer.removeClass('lg-has-thumb');
34589			}
34590		};
34591		return Thumbnail;
34592	}());
34593
34594	return Thumbnail;
34595
34596})));
34597/*!
34598 * lightgallery | 2.5.0 | June 13th 2022
34599 * http://www.lightgalleryjs.com/
34600 * Copyright (c) 2020 Sachin Neravath;
34601 * @license GPLv3
34602 */
34603
34604(function (global, factory) {
34605	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
34606	typeof define === 'function' && define.amd ? define(factory) :
34607	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgVideo = factory());
34608}(this, (function () { 'use strict';
34609
34610	/*! *****************************************************************************
34611	Copyright (c) Microsoft Corporation.
34612
34613	Permission to use, copy, modify, and/or distribute this software for any
34614	purpose with or without fee is hereby granted.
34615
34616	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
34617	REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
34618	AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
34619	INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
34620	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
34621	OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
34622	PERFORMANCE OF THIS SOFTWARE.
34623	***************************************************************************** */
34624
34625	var __assign = function() {
34626		__assign = Object.assign || function __assign(t) {
34627			for (var s, i = 1, n = arguments.length; i < n; i++) {
34628				s = arguments[i];
34629				for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
34630			}
34631			return t;
34632		};
34633		return __assign.apply(this, arguments);
34634	};
34635
34636	var videoSettings = {
34637		autoplayFirstVideo: true,
34638		youTubePlayerParams: false,
34639		vimeoPlayerParams: false,
34640		wistiaPlayerParams: false,
34641		gotoNextSlideOnVideoEnd: true,
34642		autoplayVideoOnSlide: false,
34643		videojs: false,
34644		videojsTheme: '',
34645		videojsOptions: {},
34646	};
34647
34648	/**
34649	 * List of lightGallery events
34650	 * All events should be documented here
34651	 * Below interfaces are used to build the website documentations
34652	 * */
34653	var lGEvents = {
34654		afterAppendSlide: 'lgAfterAppendSlide',
34655		init: 'lgInit',
34656		hasVideo: 'lgHasVideo',
34657		containerResize: 'lgContainerResize',
34658		updateSlides: 'lgUpdateSlides',
34659		afterAppendSubHtml: 'lgAfterAppendSubHtml',
34660		beforeOpen: 'lgBeforeOpen',
34661		afterOpen: 'lgAfterOpen',
34662		slideItemLoad: 'lgSlideItemLoad',
34663		beforeSlide: 'lgBeforeSlide',
34664		afterSlide: 'lgAfterSlide',
34665		posterClick: 'lgPosterClick',
34666		dragStart: 'lgDragStart',
34667		dragMove: 'lgDragMove',
34668		dragEnd: 'lgDragEnd',
34669		beforeNextSlide: 'lgBeforeNextSlide',
34670		beforePrevSlide: 'lgBeforePrevSlide',
34671		beforeClose: 'lgBeforeClose',
34672		afterClose: 'lgAfterClose',
34673		rotateLeft: 'lgRotateLeft',
34674		rotateRight: 'lgRotateRight',
34675		flipHorizontal: 'lgFlipHorizontal',
34676		flipVertical: 'lgFlipVertical',
34677		autoplay: 'lgAutoplay',
34678		autoplayStart: 'lgAutoplayStart',
34679		autoplayStop: 'lgAutoplayStop',
34680	};
34681
34682	var param = function (obj) {
34683		return Object.keys(obj)
34684			.map(function (k) {
34685			return encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]);
34686		})
34687			.join('&');
34688	};
34689	var getVimeoURLParams = function (defaultParams, videoInfo) {
34690		if (!videoInfo || !videoInfo.vimeo)
34691			return '';
34692		var urlParams = videoInfo.vimeo[2] || '';
34693		var defaultPlayerParams = defaultParams && Object.keys(defaultParams).length !== 0
34694			? '&' + param(defaultParams)
34695			: '';
34696		// Support private video
34697		var urlWithHash = videoInfo.vimeo[0].split('/').pop() || '';
34698		var urlWithHashWithParams = urlWithHash.split('?')[0] || '';
34699		var hash = urlWithHashWithParams.split('#')[0];
34700		var isPrivate = videoInfo.vimeo[1] !== hash;
34701		if (isPrivate) {
34702			urlParams = urlParams.replace("/" + hash, '');
34703		}
34704		urlParams =
34705			urlParams[0] == '?' ? '&' + urlParams.slice(1) : urlParams || '';
34706		// For vimeo last params gets priority if duplicates found
34707		// Uncode edit ##START##
34708		var vimeoPlayerParams = '?autoplay=0';
34709		if ( videoInfo.autoplay !== '' ) {
34710			vimeoPlayerParams = vimeoPlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1$3' );
34711			vimeoPlayerParams = vimeoPlayerParams.replace(new RegExp('([?&])autoplay(&|$)'), '$1$2' );
34712		} else {
34713			if ( typeof SiteParameters !== 'undefined' && typeof SiteParameters.vimeoPlayerParams !== 'undefined' && SiteParameters.vimeoPlayerParams !== '' ) {
34714				vimeoPlayerParams = SiteParameters.vimeoPlayerParams;
34715			}
34716		}
34717		if ( videoInfo.muted !== '' ) {
34718			vimeoPlayerParams += '&muted=' + (videoInfo.muted === 'yes');
34719		} else {
34720			if ( urlParams.indexOf('muted=') < 0 && vimeoPlayerParams.indexOf('muted=') < 0 ) {
34721				vimeoPlayerParams += '&muted=1';
34722			}
34723		}
34724		// var vimeoPlayerParams = "?autoplay=0&muted=1" + (isPrivate ? "&h=" + hash : '') + defaultPlayerParams + urlParams;
34725		vimeoPlayerParams += (isPrivate ? "&h=" + hash : '') + defaultPlayerParams + urlParams;
34726		// Uncode edit ##END##
34727		return vimeoPlayerParams;
34728	};
34729
34730	/**
34731	 * Video module for lightGallery
34732	 * Supports HTML5, YouTube, Vimeo, wistia videos
34733	 *
34734	 *
34735	 * @ref Wistia
34736	 * https://wistia.com/support/integrations/wordpress(How to get url)
34737	 * https://wistia.com/support/developers/embed-options#using-embed-options
34738	 * https://wistia.com/support/developers/player-api
34739	 * https://wistia.com/support/developers/construct-an-embed-code
34740	 * http://jsfiddle.net/xvnm7xLm/
34741	 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
34742	 * https://wistia.com/support/embed-and-share/sharing-videos
34743	 * https://private-sharing.wistia.com/medias/mwhrulrucj
34744	 *
34745	 * @ref Youtube
34746	 * https://developers.google.com/youtube/player_parameters#enablejsapi
34747	 * https://developers.google.com/youtube/iframe_api_reference
34748	 * https://developer.chrome.com/blog/autoplay/#iframe-delegation
34749	 *
34750	 * @ref Vimeo
34751	 * https://stackoverflow.com/questions/10488943/easy-way-to-get-vimeo-id-from-a-vimeo-url
34752	 * https://vimeo.zendesk.com/hc/en-us/articles/360000121668-Starting-playback-at-a-specific-timecode
34753	 * https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Using-Player-Parameters
34754	 */
34755	var Video = /** @class */ (function () {
34756		function Video(instance) {
34757			// get lightGallery core plugin instance
34758			this.core = instance;
34759			this.settings = __assign(__assign({}, videoSettings), this.core.settings);
34760			return this;
34761		}
34762		Video.prototype.init = function () {
34763			var _this = this;
34764			/**
34765			 * Event triggered when video url found without poster
34766			 * Append video HTML
34767			 * Play if autoplayFirstVideo is true
34768			 */
34769			this.core.LGel.on(lGEvents.hasVideo + ".video", this.onHasVideo.bind(this));
34770			this.core.LGel.on(lGEvents.posterClick + ".video", function () {
34771				var $el = _this.core.getSlideItem(_this.core.index);
34772				_this.loadVideoOnPosterClick($el);
34773			});
34774			this.core.LGel.on(lGEvents.slideItemLoad + ".video", this.onSlideItemLoad.bind(this));
34775			// @desc fired immediately before each slide transition.
34776			this.core.LGel.on(lGEvents.beforeSlide + ".video", this.onBeforeSlide.bind(this));
34777			// @desc fired immediately after each slide transition.
34778			this.core.LGel.on(lGEvents.afterSlide + ".video", this.onAfterSlide.bind(this));
34779		};
34780		/**
34781		 * @desc Event triggered when a slide is completely loaded
34782		 *
34783		 * @param {Event} event - lightGalley custom event
34784		 */
34785		Video.prototype.onSlideItemLoad = function (event) {
34786			var _this = this;
34787			var _a = event.detail, isFirstSlide = _a.isFirstSlide, index = _a.index;
34788			// Should check the active slide as well as user may have moved to different slide before the first slide is loaded
34789			if (this.settings.autoplayFirstVideo &&
34790				isFirstSlide &&
34791				index === this.core.index) {
34792				// Delay is just for the transition effect on video load
34793				setTimeout(function () {
34794					_this.loadAndPlayVideo(index);
34795				}, 200);
34796			}
34797			// Should not call on first slide. should check only if the slide is active
34798			if (!isFirstSlide &&
34799				this.settings.autoplayVideoOnSlide &&
34800				index === this.core.index) {
34801					setTimeout(function () {
34802						_this.loadAndPlayVideo(index);
34803					}, 500);
34804				}
34805		};
34806		/**
34807		 * @desc Event triggered when video url or poster found
34808		 * Append video HTML is poster is not given
34809		 * Play if autoplayFirstVideo is true
34810		 *
34811		 * @param {Event} event - Javascript Event object.
34812		 */
34813		Video.prototype.onHasVideo = function (event) {
34814			var _a = event.detail, index = _a.index, src = _a.src, html5Video = _a.html5Video, hasPoster = _a.hasPoster;
34815			if (!hasPoster) {
34816				// All functions are called separately if poster exist in loadVideoOnPosterClick function
34817				this.appendVideos(this.core.getSlideItem(index), {
34818					src: src,
34819					addClass: 'lg-object',
34820					index: index,
34821					html5Video: html5Video,
34822					// Uncode edit ##START##
34823					autoplay: event.target.getAttribute('data-lb-autoplay'),
34824					muted: event.target.getAttribute('data-lb-muted'),
34825					// Uncode edit ##END##
34826				});
34827				// Automatically navigate to next slide once video reaches the end.
34828				this.gotoNextSlideOnVideoEnd(src, index);
34829			}
34830		};
34831		/**
34832		 * @desc fired immediately before each slide transition.
34833		 * Pause the previous video
34834		 * Hide the download button if the slide contains YouTube, Vimeo, or Wistia videos.
34835		 *
34836		 * @param {Event} event - Javascript Event object.
34837		 * @param {number} prevIndex - Previous index of the slide.
34838		 * @param {number} index - Current index of the slide
34839		 */
34840		Video.prototype.onBeforeSlide = function (event) {
34841			if (this.core.lGalleryOn) {
34842				var prevIndex = event.detail.prevIndex;
34843				this.pauseVideo(prevIndex);
34844			}
34845			// Uncode edit ##START##
34846			var _a = event.detail, index = _a.index;
34847			var $slide = this.core.getSlideItem(index);
34848			
34849			var iframe = $slide.selector.querySelector('iframe');
34850			if ( iframe != null ) {
34851
34852				var data_play = iframe.getAttribute('data-autoplay');
34853				if ( typeof data_play !== 'undefined' && data_play === '1' ) {
34854					this.loadAndPlayVideo(index);
34855
34856					var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {},
34857						$videoElement = this.core.getSlideItem(index).find('.lg-video-object').first();
34858					if (videoInfo.vimeo) {
34859						var vimeoPlayer = new Vimeo.Player($videoElement.get());
34860						vimeoPlayer.on('play', function () {
34861							vimeoPlayer.setCurrentTime(0);
34862						});
34863					} else if ( videoInfo.youtube ) {
34864						try {
34865							$videoElement.get().contentWindow.postMessage("{\"event\":\"command\",\"func\":\"seekTo\",\"args\":[0, true]}", '*');
34866						}
34867						catch (e) {
34868							console.warn(e);
34869						}
34870					}
34871				}
34872			}
34873			// Uncode edit ##END##
34874		};
34875		/**
34876		 * @desc fired immediately after each slide transition.
34877		 * Play video if autoplayVideoOnSlide option is enabled.
34878		 *
34879		 * @param {Event} event - Javascript Event object.
34880		 * @param {number} prevIndex - Previous index of the slide.
34881		 * @param {number} index - Current index of the slide
34882		 * @todo should check on onSlideLoad as well if video is not loaded on after slide
34883		 */
34884		Video.prototype.onAfterSlide = function (event) {
34885			var _this = this;
34886			var _a = event.detail, index = _a.index, prevIndex = _a.prevIndex;
34887			// Do not call on first slide
34888			var $slide = this.core.getSlideItem(index);
34889			if (this.settings.autoplayVideoOnSlide && index !== prevIndex) {
34890				if ($slide.hasClass('lg-complete')) {
34891					setTimeout(function () {
34892						_this.loadAndPlayVideo(index);
34893					}, 100);
34894				}
34895			}
34896		};
34897		Video.prototype.loadAndPlayVideo = function (index) {
34898			var $slide = this.core.getSlideItem(index);
34899			var currentGalleryItem = this.core.galleryItems[index];
34900			if (currentGalleryItem.poster) {
34901				this.loadVideoOnPosterClick($slide, true);
34902			}
34903			else {
34904				//Uncode edit ##START##
34905				// this.playVideo(index);
34906				var iframe = $slide.selector.querySelector('iframe');
34907				if ( iframe != null ) {
34908					var data_play = iframe.getAttribute('data-autoplay');
34909					if ( typeof data_play !== 'undefined' ) {
34910						if ( data_play === '1' && this.core.index == index ) {
34911							this.playVideo(index);
34912						} else {
34913							this.pauseVideo(index);
34914						}
34915					}
34916				}
34917				//Uncode edit ##END##
34918			}
34919		};
34920		/**
34921		 * Play HTML5, Youtube, Vimeo or Wistia videos in a particular slide.
34922		 * @param {number} index - Index of the slide
34923		 */
34924		Video.prototype.playVideo = function (index) {
34925			this.controlVideo(index, 'play');
34926		};
34927		/**
34928		 * Pause HTML5, Youtube, Vimeo or Wistia videos in a particular slide.
34929		 * @param {number} index - Index of the slide
34930		 */
34931		Video.prototype.pauseVideo = function (index) {
34932			this.controlVideo(index, 'pause');
34933		};
34934		// Uncode edit ##START##
34935		//Video.prototype.getVideoHtml = function (src, addClass, index, html5Video) {
34936		Video.prototype.getVideoHtml = function (src, addClass, index, html5Video, autoplay, muted) {
34937		// Uncode edit ##END##
34938			var video = '';
34939			var videoInfo = this.core.galleryItems[index]
34940				.__slideVideoInfo || {};
34941			var currentGalleryItem = this.core.galleryItems[index];
34942			var videoTitle = currentGalleryItem.title || currentGalleryItem.alt;
34943			videoTitle = videoTitle ? 'title="' + videoTitle + '"' : '';
34944			var commonIframeProps = "allowtransparency=\"true\"\n            frameborder=\"0\"\n            scrolling=\"no\"\n            allowfullscreen\n            mozallowfullscreen\n            webkitallowfullscreen\n            oallowfullscreen\n            msallowfullscreen";
34945			if (videoInfo.youtube) {
34946				var videoId = 'lg-youtube' + index;
34947				var slideUrlParams = videoInfo.youtube[2]
34948					? videoInfo.youtube[2] + '&'
34949					: '';
34950				// For youtube first parms gets priority if duplicates found
34951				// Uncode edit ##START##
34952				// var youTubePlayerParams = "?" + slideUrlParams + "wmode=opaque&autoplay=0&mute=1&enablejsapi=1";
34953				var youTubePlayerParams = "?" + slideUrlParams + "wmode=opaque&enablejsapi=1";
34954				if ( ( slideUrlParams.indexOf('autoplay=') < 0 && youTubePlayerParams.indexOf('autoplay=') < 0 ) ) {
34955					youTubePlayerParams += '&autoplay=0';
34956				}
34957				if ( slideUrlParams.indexOf('mute=') < 0 && youTubePlayerParams.indexOf('mute=') < 0 ) {
34958					youTubePlayerParams += '&mute=1';
34959				}
34960				var data_video = '';
34961				if ( autoplay !== '' ) {
34962					//youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1autoplay=' + (autoplay === 'yes' ? 1 : 0) + '$3' );
34963					youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay=(.*?)(&|$)'), '$1$3' );
34964					youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])autoplay'), '$1' );
34965					data_video = ' data-autoplay="' + (autoplay === 'yes' ? 1 : 0) + '"';
34966				}
34967				// if ( muted !== '' ) {
34968				// 	youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])mute=(.*?)(&|$)'), '$1mute=' + (muted === 'yes' ? 1 : 0) + '$3' );
34969				// }
34970				youTubePlayerParams = youTubePlayerParams.replace(new RegExp('([?&])mute=(.*?)(&|$)'), '$1$3' );
34971
34972				youTubePlayerParams = youTubePlayerParams.replace('??', '?');
34973				// Uncode edit ##END##
34974				var playerParams = youTubePlayerParams +
34975					(this.settings.youTubePlayerParams
34976						? '&' + param(this.settings.youTubePlayerParams)
34977						: '');
34978				// Uncode edit ##START##
34979				// video = "<iframe allow=\"autoplay\" id=" + videoId + " class=\"lg-video-object lg-youtube " + addClass + "\" " + videoTitle + " src=\"//www.youtube.com/embed/" + (videoInfo.youtube[1] + playerParams) + "\" " + commonIframeProps + "></iframe>";
34980				var nocookie = typeof SiteParameters.uncode_nocookie !== 'undefined' ? SiteParameters.uncode_nocookie : '';
34981				video = "<iframe allow=\"autoplay\"" + data_video + " id=" + videoId + " class=\"lg-video-object lg-youtube " + addClass + "\" " + videoTitle + " src=\"//www.youtube" + nocookie + ".com/embed/" + (videoInfo.youtube[1] + playerParams) + "\" " + commonIframeProps + "></iframe>";
34982				var tag = document.createElement('script');
34983				tag.src = "//www.youtube.com/player_api";
34984				var firstScriptTag = document.getElementsByTagName('script')[0];
34985				firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
34986
34987				// Replace the 'ytplayer' element with an <iframe> and
34988				// YouTube player after the API code downloads.
34989				var ytIframeplayer,
34990					setMute = muted === 'yes' ? 0 : 100;
34991				window.onYouTubePlayerAPIReady = function() {
34992					ytIframeplayer = new YT.Player(videoId, {
34993						videoId: videoInfo.youtube[1],
34994						events: {
34995							'onReady': function (event) {
34996								event.target.setVolume(setMute);
34997							}
34998						}
34999					});
35000				}
35001				// Uncode edit ##END##
35002			}
35003			else if (videoInfo.vimeo) {
35004				var videoId = 'lg-vimeo' + index;
35005				// Uncode edit ##START##
35006				videoInfo.autoplay = autoplay;
35007				videoInfo.muted = muted;
35008				// Uncode edit ##END##
35009				var playerParams = getVimeoURLParams(this.settings.vimeoPlayerParams, videoInfo);
35010				// Uncode edit ##START##
35011				// video = "<iframe allow=\"autoplay\" id=" + videoId + " class=\"lg-video-object lg-vimeo " + addClass + "\" " + videoTitle + " src=\"//player.vimeo.com/video/" + (videoInfo.vimeo[1] + playerParams) + "\" " + commonIframeProps + "></iframe>";
35012				var data_video = '';
35013				if ( autoplay !== '' ) {
35014					data_video = ' data-autoplay="' + (autoplay === 'yes' ? 1 : 0) + '"';
35015				}
35016				video = "<iframe allow=\"autoplay\"" + data_video + " id=" + videoId + " class=\"lg-video-object lg-vimeo " + addClass + "\" " + videoTitle + " src=\"//player.vimeo.com/video/" + (videoInfo.vimeo[1] + playerParams) + "\" " + commonIframeProps + "></iframe>";
35017				// Uncode edit ##END##
35018			}
35019			else if (videoInfo.wistia) {
35020				var wistiaId = 'lg-wistia' + index;
35021				var playerParams = param(this.settings.wistiaPlayerParams);
35022				playerParams = playerParams ? '?' + playerParams : '';
35023				video = "<iframe allow=\"autoplay\" id=\"" + wistiaId + "\" src=\"//fast.wistia.net/embed/iframe/" + (videoInfo.wistia[4] + playerParams) + "\" " + videoTitle + " class=\"wistia_embed lg-video-object lg-wistia " + addClass + "\" name=\"wistia_embed\" " + commonIframeProps + "></iframe>";
35024			}
35025			else if (videoInfo.html5) {
35026				var html5VideoMarkup = '';
35027				for (var i = 0; i < html5Video.source.length; i++) {
35028					html5VideoMarkup += "<source src=\"" + html5Video.source[i].src + "\" type=\"" + html5Video.source[i].type + "\">";
35029				}
35030				if (html5Video.tracks) {
35031					var _loop_1 = function (i) {
35032						var trackAttributes = '';
35033						var track = html5Video.tracks[i];
35034						Object.keys(track || {}
35034).forEach(function (key) {
35035							trackAttributes += key + "=\"" + track[key] + "\" ";
35036						});
35037						html5VideoMarkup += "<track " + trackAttributes + ">";
35038					};
35039					for (var i = 0; i < html5Video.tracks.length; i++) {
35040						_loop_1(i);
35041					}
35042				}
35043				var html5VideoAttrs_1 = '';
35044				var videoAttributes_1 = html5Video.attributes || {};
35045				Object.keys(videoAttributes_1 || {}).forEach(function (key) {
35046					html5VideoAttrs_1 += key + "=\"" + videoAttributes_1[key] + "\" ";
35047				});
35048				video = "<video class=\"lg-video-object lg-html5 " + (this.settings.videojs && this.settings.videojsTheme
35049					? this.settings.videojsTheme + ' '
35050					: '') + " " + (this.settings.videojs ? ' video-js' : '') + "\" " + html5VideoAttrs_1 + ">\n                " + html5VideoMarkup + "\n                Your browser does not support HTML5 video.\n            </video>";
35051			}
35052			return video;
35053		};
35054		/**
35055		 * @desc - Append videos to the slide
35056		 *
35057		 * @param {HTMLElement} el - slide element
35058		 * @param {Object} videoParams - Video parameters, Contains src, class, index, htmlVideo
35059		 */
35060		Video.prototype.appendVideos = function (el, videoParams) {
35061			var _a;
35062			// Uncode edit ##START##
35063			// var videoHtml = this.getVideoHtml(videoParams.src, videoParams.addClass, videoParams.index, videoParams.html5Video);
35064			var videoHtml = this.getVideoHtml(videoParams.src, videoParams.addClass, videoParams.index, videoParams.html5Video, videoParams.autoplay, videoParams.muted);
35065			// Uncode edit ##END##
35066			el.find('.lg-video-cont').append(videoHtml);
35067			var $videoElement = el.find('.lg-video-object').first();
35068			if (videoParams.html5Video) {
35069				$videoElement.on('mousedown.lg.video', function (e) {
35070					e.stopPropagation();
35071				});
35072			}
35073			if (this.settings.videojs && ((_a = this.core.galleryItems[videoParams.index].__slideVideoInfo) === null || _a === void 0 ? void 0 : _a.html5)) {
35074				try {
35075					return videojs($videoElement.get(), this.settings.videojsOptions);
35076				}
35077				catch (e) {
35078					console.warn('lightGallery:- Make sure you have included videojs');
35079				}
35080			}
35081		};
35082		Video.prototype.gotoNextSlideOnVideoEnd = function (src, index) {
35083			var _this = this;
35084			var $videoElement = this.core
35085				.getSlideItem(index)
35086				.find('.lg-video-object')
35087				.first();
35088			var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {};
35089			if (this.settings.gotoNextSlideOnVideoEnd) {
35090				if (videoInfo.html5) {
35091					$videoElement.on('ended', function () {
35092						_this.core.goToNextSlide();
35093					});
35094				}
35095				else if (videoInfo.vimeo) {
35096					try {
35097						// https://github.com/vimeo/player.js/#ended
35098						new Vimeo.Player($videoElement.get()).on('ended', function () {
35099							_this.core.goToNextSlide();
35100						});
35101					}
35102					catch (e) {
35103						console.warn('lightGallery:- Make sure you have included //github.com/vimeo/player.js');
35104					}
35105				}
35106				else if (videoInfo.wistia) {
35107					try {
35108						window._wq = window._wq || [];
35109						// @todo Event is gettign triggered multiple times
35110						window._wq.push({
35111							id: $videoElement.attr('id'),
35112							onReady: function (video) {
35113								video.bind('end', function () {
35114									_this.core.goToNextSlide();
35115								});
35116							},
35117						});
35118					}
35119					catch (e) {
35120						console.warn('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js');
35121					}
35122				}
35123			}
35124		};
35125		Video.prototype.controlVideo = function (index, action) {
35126			var $videoElement = this.core
35127				.getSlideItem(index)
35128				.find('.lg-video-object')
35129				.first();
35130			var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {};
35131			if (!$videoElement.get())
35132				return;
35133			if (videoInfo.youtube) {
35134				try {
35135					$videoElement.get().contentWindow.postMessage("{\"event\":\"command\",\"func\":\"" + action + "Video\",\"args\":\"\"}", '*');
35136				}
35137				catch (e) {
35138					console.warn("lightGallery:- " + e);
35139				}
35140			}
35141			else if (videoInfo.vimeo) {
35142				try {
35143					new Vimeo.Player($videoElement.get())[action]();
35144				}
35145				catch (e) {
35146					console.warn('lightGallery:- Make sure you have included //github.com/vimeo/player.js');
35147				}
35148			}
35149			else if (videoInfo.html5) {
35150				if (this.settings.videojs) {
35151					try {
35152						videojs($videoElement.get())[action]();
35153					}
35154					catch (e) {
35155						console.warn('lightGallery:- Make sure you have included videojs');
35156					}
35157				}
35158				else {
35159					$videoElement.get()[action]();
35160				}
35161			}
35162			else if (videoInfo.wistia) {
35163				try {
35164					window._wq = window._wq || [];
35165					// @todo Find a way to destroy wistia player instance
35166					window._wq.push({
35167						id: $videoElement.attr('id'),
35168						onReady: function (video) {
35169							video[action]();
35170						},
35171					});
35172				}
35173				catch (e) {
35174					console.warn('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js');
35175				}
35176			}
35177		};
35178		Video.prototype.loadVideoOnPosterClick = function ($el, forcePlay) {
35179			var _this = this;
35180			// check slide has poster
35181			if (!$el.hasClass('lg-video-loaded')) {
35182				// check already video element present
35183				if (!$el.hasClass('lg-has-video')) {
35184					$el.addClass('lg-has-video');
35185					var _html = void 0;
35186					var _src = this.core.galleryItems[this.core.index].src;
35187					var video = this.core.galleryItems[this.core.index].video;
35188					if (video) {
35189						_html =
35190							typeof video === 'string' ? JSON.parse(video) : video;
35191					}
35192					var videoJsPlayer_1 = this.appendVideos($el, {
35193						src: _src,
35194						addClass: '',
35195						index: this.core.index,
35196						html5Video: _html,
35197					});
35198					this.gotoNextSlideOnVideoEnd(_src, this.core.index);
35199					var $tempImg = $el.find('.lg-object').first().get();
35200					// @todo make sure it is working
35201					$el.find('.lg-video-cont').first().append($tempImg);
35202					$el.addClass('lg-video-loading');
35203					videoJsPlayer_1 &&
35204						videoJsPlayer_1.ready(function () {
35205							videoJsPlayer_1.on('loadedmetadata', function () {
35206								_this.onVideoLoadAfterPosterClick($el, _this.core.index);
35207							});
35208						});
35209					$el.find('.lg-video-object')
35210						.first()
35211						.on('load.lg error.lg loadedmetadata.lg', function () {
35212						setTimeout(function () {
35213							_this.onVideoLoadAfterPosterClick($el, _this.core.index);
35214						}, 50);
35215					});
35216				}
35217				else {
35218					this.playVideo(this.core.index);
35219				}
35220			}
35221			else if (forcePlay) {
35222				this.playVideo(this.core.index);
35223			}
35224		};
35225		Video.prototype.onVideoLoadAfterPosterClick = function ($el, index) {
35226			$el.addClass('lg-video-loaded');
35227			this.playVideo(index);
35228		};
35229		Video.prototype.destroy = function () {
35230			this.core.LGel.off('.lg.video');
35231			this.core.LGel.off('.video');
35232		};
35233		return Video;
35234	}());
35235
35236	return Video;
35237
35238})));
35239
35240
35241/*! @vimeo/player v2.17.1 | (c) 2022 Vimeo | MIT License | https://github.com/vimeo/player.js */
35242!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).Vimeo=e.Vimeo||{},e.Vimeo.Player=t())}(this,function(){"use strict";function r(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var e="undefined"!=typeof global&&"[object global]"==={}.toString.call(global);function i(e,t){return 0===e.indexOf(t.toLowerCase())?e:"".concat(t.toLowerCase()).concat(e.substr(0,1).toUpperCase()).concat(e.substr(1))}function c(e){return/^(https?:)?\/\/((player|www)\.)?vimeo\.com(?=$|\/)/.test(e)}function s(e){var t,n=0<arguments.length&&void 0!==e?e:{},r=n.id,o=n.url,i=r||o;if(!i)throw new Error("An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.");if(t=i,!isNaN(parseFloat(t))&&isFinite(t)&&Math.floor(t)==t)return"https://vimeo.com/".concat(i);if(c(i))return i.replace("http:","https:");if(r)throw new TypeError("“".concat(r,"” is not a valid video id."));throw new TypeError("“".concat(i,"” is not a vimeo.com url."))}var t=void 0!==Array.prototype.indexOf,n="undefined"!=typeof window&&void 0!==window.postMessage;if(!(e||t&&n))throw new Error("Sorry, the Vimeo Player API is not available in this browser.");var o,a,u,l,f="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function d(){if(void 0===this)throw new TypeError("Constructor WeakMap requires 'new'");if(l(this,"_id","_WeakMap_"+v()+"."+v()),0<arguments.length)throw new TypeError("WeakMap iterable is not supported")}function h(e,t){if(!m(e)||!a.call(e,"_id"))throw new TypeError(t+" method called on incompatible receiver "+typeof e)}function v(){return Math.random().toString().substring(2)}function m(e){return Object(e)===e}(o="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:"undefined"!=typeof window?window:f).WeakMap||(a=Object.prototype.hasOwnProperty,u=Object.defineProperty&&function(){try{return 1===Object.defineProperty({},"x",{value:1}).x}catch(e){}}(),l=function(e,t,n){u?Object.defineProperty(e,t,{configurable:!0,writable:!0,value:n}):e[t]=n},o.WeakMap=(l(d.prototype,"delete",function(e){if(h(this,"delete"),!m(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)&&(delete e[this._id],!0)}),l(d.prototype,"get",function(e){if(h(this,"get"),m(e)){var t=e[this._id];return t&&t[0]===e?t[1]:void 0}}),l(d.prototype,"has",function(e){if(h(this,"has"),!m(e))return!1;var t=e[this._id];return!(!t||t[0]!==e)}),l(d.prototype,"set",function(e,t){if(h(this,"set"),!m(e))throw new TypeError("Invalid value used as weak map key");var n=e[this._id];return n&&n[0]===e?n[1]=t:l(e,this._id,[e,t]),this}),l(d,"_polyfill",!0),d));var p,y=(function(e){var t,n,r;r=function(){var t,n,r,o,i,a,e=Object.prototype.toString,u="undefined"!=typeof setImmediate?function(e){return setImmediate(e)}:setTimeout;try{Object.defineProperty({},"x",{}),t=function(e,t,n,r){return Object.defineProperty(e,t,{value:n,writable:!0,configurable:!1!==r})}}catch(e){t=function(e,t,n){return e[t]=n,e}}function l(e,t){this.fn=e,this.self=t,this.next=void 0}function c(e,t){r.add(e,t),n=n||u(r.drain)}function s(e){var t,n=typeof e;return null==e||"object"!=n&&"function"!=n||(t=e.then),"function"==typeof t&&t}function f(){for(var e=0;e<this.chain.length;e++)!function(e,t,n){var r,o;try{!1===t?n.reject(e.msg):(r=!0===t?e.msg:t.call(void 0,e.msg))===n.promise?n.reject(TypeError("Promise-chain cycle")):(o=s(r))?o.call(r,n.resolve,n.reject):n.resolve(r)}catch(e){n.reject(e)}}(this,1===this.state?this.chain[e].success:this.chain[e].failure,this.chain[e]);this.chain.length=0}function d(e){var n,r=this;if(!r.triggered){r.triggered=!0,r.def&&(r=r.def);try{(n=s(e))?c(function(){var t=new m(r);try{n.call(e,function(){d.apply(t,arguments)},function(){h.apply(t,arguments)})}catch(e){h.call(t,e)}}):(r.msg=e,r.state=1,0<r.chain.length&&c(f,r))}catch(e){h.call(new m(r),e)}}}function h(e){var t=this;t.triggered||(t.triggered=!0,t.def&&(t=t.def),t.msg=e,t.state=2,0<t.chain.length&&c(f,t))}function v(e,n,r,o){for(var t=0;t<n.length;t++)!function(t){e.resolve(n[t]).then(function(e){r(t,e)},o)}(t)}function m(e){this.def=e,this.triggered=!1}function p(e){this.promise=e,this.state=0,this.triggered=!1,this.chain=[],this.msg=void 0}function y(e){if("function"!=typeof e)throw TypeError("Not a function");if(0!==this.__NPO__)throw TypeError("Not a promise");this.__NPO__=1;var r=new p(this);this.then=function(e,t){var n={success:"function"!=typeof e||e,failure:"function"==typeof t&&t};return n.promise=new this.constructor(function(e,t){if("function"!=typeof e||"function"!=typeof t)throw TypeError("Not a function");n.resolve=e,n.reject=t}),r.chain.push(n),0!==r.state&&c(f,r),n.promise},this.catch=function(e){return this.then(void 0,e)};try{e.call(void 0,function(e){d.call(r,e)},function(e){h.call(r,e)})}catch(e){h.call(r,e)}}var g=t({},"constructor",y,!(r={add:function(e,t){a=new l(e,t),i?i.next=a:o=a,i=a,a=void 0},drain:function(){var e=o;for(o=i=n=void 0;e;)e.fn.call(e.self),e=e.next}}));return t(y.prototype=g,"__NPO__",0,!1),t(y,"resolve",function(n){return n&&"object"==typeof n&&1===n.__NPO__?n:new this(function(e,t){if("function"!=typeof e||"function"!=typeof t)throw TypeError("Not a function");e(n)})}),t(y,"reject",function(n){return new this(function(e,t){if("function"!=typeof e||"function"!=typeof t)throw TypeError("Not a function");t(n)})}),t(y,"all",function(t){var a=this;return"[object Array]"!=e.call(t)?a.reject(TypeError("Not an array")):0===t.length?a.resolve([]):new a(function(n,e){if("function"!=typeof n||"function"!=typeof e)throw TypeError("Not a function");var r=t.length,o=Array(r),i=0;v(a,t,function(e,t){o[e]=t,++i===r&&n(o)},e)})}),t(y,"race",function(t){var r=this;return"[object Array]"!=e.call(t)?r.reject(TypeError("Not an array")):new r(function(n,e){if("function"!=typeof n||"function"!=typeof e)throw TypeError("Not a function");v(r,t,function(e,t){n(t)},e)})}),y},(n=f)[t="Promise"]=n[t]||r(),e.exports&&(e.exports=n[t])}(p={exports:{}}
35242),p.exports),g=new WeakMap;function w(e,t,n){var r=g.get(e.element)||{};t in r||(r[t]=[]),r[t].push(n),g.set(e.element,r)}function b(e,t){return(g.get(e.element)||{})[t]||[]}function k(e,t,n){var r=g.get(e.element)||{};if(!r[t])return!0;if(!n)return r[t]=[],g.set(e.element,r),!0;var o=r[t].indexOf(n);return-1!==o&&r[t].splice(o,1),g.set(e.element,r),r[t]&&0===r[t].length}function E(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){return console.warn(e),{}}return e}function T(e,t,n){var r,o;e.element.contentWindow&&e.element.contentWindow.postMessage&&(r={method:t},void 0!==n&&(r.value=n),8<=(o=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\d+).*$/,"$1")))&&o<10&&(r=JSON.stringify(r)),e.element.contentWindow.postMessage(r,e.origin))}function P(n,r){var t,e,o=[];(r=E(r)).event?("error"===r.event&&b(n,r.data.method).forEach(function(e){var t=new Error(r.data.message);t.name=r.data.name,e.reject(t),k(n,r.data.method,e)}),o=b(n,"event:".concat(r.event)),t=r.data):!r.method||(e=function(e,t){var n=b(e,t);if(n.length<1)return!1;var r=n.shift();return k(e,t,r),r}(n,r.method))&&(o.push(e),t=r.value),o.forEach(function(e){try{if("function"==typeof e)return void e.call(n,t);e.resolve(t)}catch(e){}})}var M=["autopause","autoplay","background","byline","color","controls","dnt","height","id","interactive_params","keyboard","loop","maxheight","maxwidth","muted","playsinline","portrait","responsive","speed","texttrack","title","transparent","url","width"];function _(r,e){var t=1<arguments.length&&void 0!==e?e:{};return M.reduce(function(e,t){var n=r.getAttribute("data-vimeo-".concat(t));return!n&&""!==n||(e[t]=""===n?1:n),e},t)}function N(e,t){var n=e.html;if(!t)throw new TypeError("An element must be provided");if(null!==t.getAttribute("data-vimeo-initialized"))return t.querySelector("iframe");var r=document.createElement("div");return r.innerHTML=n,t.appendChild(r.firstChild),t.setAttribute("data-vimeo-initialized","true"),t.querySelector("iframe")}function F(i,e,t){var a=1<arguments.length&&void 0!==e?e:{},u=2<arguments.length?t:void 0;return new Promise(function(t,n){if(!c(i))throw new TypeError("“".concat(i,"” is not a vimeo.com url."));var e="https://vimeo.com/api/oembed.json?url=".concat(encodeURIComponent(i));for(var r in a)a.hasOwnProperty(r)&&(e+="&".concat(r,"=").concat(encodeURIComponent(a[r])));var o=new("XDomainRequest"in window?XDomainRequest:XMLHttpRequest);o.open("GET",e,!0),o.onload=function(){if(404!==o.status)if(403!==o.status)try{var e=JSON.parse(o.responseText);if(403===e.domain_status_code)return N(e,u),void n(new Error("“".concat(i,"” is not embeddable.")));t(e)}catch(e){n(e)}else n(new Error("“".concat(i,"” is not embeddable.")));else n(new Error("“".concat(i,"” was not found.")))},o.onerror=function(){var e=o.status?" (".concat(o.status,")"):"";n(new Error("There was an error fetching the embed code from Vimeo".concat(e,".")))},o.send()})}var x,C,j,A=new WeakMap,S=new WeakMap,q={},Player=function(){function Player(u){var e,t,l=this,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,Player),window.jQuery&&u instanceof jQuery&&(1<u.length&&window.console&&console.warn&&console.warn("A jQuery object with multiple elements was passed, using the first element."),u=u[0]),"undefined"!=typeof document&&"string"==typeof u&&(u=document.getElementById(u)),e=u,!Boolean(e&&1===e.nodeType&&"nodeName"in e&&e.ownerDocument&&e.ownerDocument.defaultView))throw new TypeError("You must pass either a valid element or a valid id.");if("IFRAME"===u.nodeName||(t=u.querySelector("iframe"))&&(u=t),"IFRAME"===u.nodeName&&!c(u.getAttribute("src")||""))throw new Error("The player element passed isn’t a Vimeo embed.");if(A.has(u))return A.get(u);this._window=u.ownerDocument.defaultView,this.element=u,this.origin="*";var r,o=new y(function(i,a){var e;l._onMessage=function(e){if(c(e.origin)&&l.element.contentWindow===e.source){"*"===l.origin&&(l.origin=e.origin);var t=E(e.data);if(t&&"error"===t.event&&t.data&&"ready"===t.data.method){var n=new Error(t.data.message);return n.name=t.data.name,void a(n)}
vendor: 9,482 bytes, line 35242
35242var r=t&&"ready"===t.event,o=t&&"ping"===t.method;if(r||o)return l.element.setAttribute("data-ready","true"),void i();P(l,t)}},l._window.addEventListener("message",l._onMessage),"IFRAME"!==l.element.nodeName&&F(s(e=_(u,n)),e,u).then(function(e){var t,n,r,o=N(e,u);return l.element=o,l._originalElement=u,t=u,n=o,r=g.get(t),g.set(n,r),g.delete(t),A.set(l.element,l),e}).catch(a)});return S.set(this,o),A.set(this.element,this),"IFRAME"===this.element.nodeName&&T(this,"ping"),q.isEnabled&&(r=function(){return q.exit()},this.fullscreenchangeHandler=function(){(q.isFullscreen?w:k)(l,"event:exitFullscreen",r),l.ready().then(function(){T(l,"fullscreenchange",q.isFullscreen)})},q.on("fullscreenchange",this.fullscreenchangeHandler)),this}var e,t,n;return e=Player,(t=[{key:"callMethod",value:function(n,e){var r=this,o=1<arguments.length&&void 0!==e?e:{};return new y(function(e,t){return r.ready().then(function(){w(r,n,{resolve:e,reject:t}),T(r,n,o)}).catch(t)})}},{key:"get",value:function(n){var r=this;return new y(function(e,t){return n=i(n,"get"),r.ready().then(function(){w(r,n,{resolve:e,reject:t}),T(r,n)}).catch(t)})}},{key:"set",value:function(n,r){var o=this;return new y(function(e,t){if(n=i(n,"set"),null==r)throw new TypeError("There must be a value to set.");return o.ready().then(function(){w(o,n,{resolve:e,reject:t}),T(o,n,r)}).catch(t)})}},{key:"on",value:function(e,t){if(!e)throw new TypeError("You must pass an event name.");if(!t)throw new TypeError("You must pass a callback function.");if("function"!=typeof t)throw new TypeError("The callback must be a function.");0===b(this,"event:".concat(e)).length&&this.callMethod("addEventListener",e).catch(function(){}),w(this,"event:".concat(e),t)}},{key:"off",value:function(e,t){if(!e)throw new TypeError("You must pass an event name.");if(t&&"function"!=typeof t)throw new TypeError("The callback must be a function.");k(this,"event:".concat(e),t)&&this.callMethod("removeEventListener",e).catch(function(e){})}},{key:"loadVideo",value:function(e){return this.callMethod("loadVideo",e)}},{key:"ready",value:function(){var e=S.get(this)||new y(function(e,t){t(new Error("Unknown player. Probably unloaded."))});return y.resolve(e)}},{key:"addCuePoint",value:function(e,t){var n=1<arguments.length&&void 0!==t?t:{};return this.callMethod("addCuePoint",{time:e,data:n})}},{key:"removeCuePoint",value:function(e){return this.callMethod("removeCuePoint",e)}},{key:"enableTextTrack",value:function(e,t){if(!e)throw new TypeError("You must pass a language.");return this.callMethod("enableTextTrack",{language:e,kind:t})}},{key:"disableTextTrack",value:function(){return this.callMethod("disableTextTrack")}},{key:"pause",value:function(){return this.callMethod("pause")}},{key:"play",value:function(){return this.callMethod("play")}},{key:"requestFullscreen",value:function(){return q.isEnabled?q.request(this.element):this.callMethod("requestFullscreen")}},{key:"exitFullscreen",value:function(){return q.isEnabled?q.exit():this.callMethod("exitFullscreen")}},{key:"getFullscreen",value:function(){return q.isEnabled?y.resolve(q.isFullscreen):this.get("fullscreen")}},{key:"requestPictureInPicture",value:function(){return this.callMethod("requestPictureInPicture")}},{key:"exitPictureInPicture",value:function(){return this.callMethod("exitPictureInPicture")}},{key:"getPictureInPicture",value:function(){return this.get("pictureInPicture")}},{key:"unload",value:function(){return this.callMethod("unload")}},{key:"destroy",value:function(){var n=this;return new y(function(e){var t;S.delete(n),A.delete(n.element),n._originalElement&&(A.delete(n._originalElement),n._originalElement.removeAttribute("data-vimeo-initialized")),n.element&&"IFRAME"===n.element.nodeName&&n.element.parentNode&&(n.element.parentNode.parentNode&&n._originalElement&&n._originalElement!==n.element.parentNode?n.element.parentNode.parentNode.removeChild(n.element.parentNode):n.element.parentNode.removeChild(n.element)),n.element&&"DIV"===n.element.nodeName&&n.element.parentNode&&(n.element.removeAttribute("data-vimeo-initialized"),(t=n.element.querySelector("iframe"))&&t.parentNode&&(t.parentNode.parentNode&&n._originalElement&&n._originalElement!==t.parentNode?t.parentNode.parentNode.removeChild(t.parentNode):t.parentNode.removeChild(t))),n._window.removeEventListener("message",n._onMessage),q.isEnabled&&q.off("fullscreenchange",n.fullscreenchangeHandler),e()})}},{key:"getAutopause",value:function(){return this.get("autopause")}},{key:"setAutopause",value:function(e){return this.set("autopause",e)}},{key:"getBuffered",value:function(){return this.get("buffered")}},{key:"getCameraProps",value:function(){return this.get("cameraProps")}},{key:"setCameraProps",value:function(e){return this.set("cameraProps",e)}},{key:"getChapters",value:function(){return this.get("chapters")}},{key:"getCurrentChapter",value:function(){return this.get("currentChapter")}},{key:"getColor",value:function(){return this.get("color")}},{key:"setColor",value:function(e){return this.set("color",e)}},{key:"getCuePoints",value:function(){return this.get("cuePoints")}},{key:"getCurrentTime",value:function(){return this.get("currentTime")}},{key:"setCurrentTime",value:function(e){return this.set("currentTime",e)}},{key:"getDuration",value:function(){return this.get("duration")}},{key:"getEnded",value:function(){return this.get("ended")}},{key:"getLoop",value:function(){return this.get("loop")}},{key:"setLoop",value:function(e){return this.set("loop",e)}},{key:"setMuted",value:function(e){return this.set("muted",e)}},{key:"getMuted",value:function(){return this.get("muted")}},{key:"getPaused",value:function(){return this.get("paused")}},{key:"getPlaybackRate",value:function(){return this.get("playbackRate")}},{key:"setPlaybackRate",value:function(e){return this.set("playbackRate",e)}},{key:"getPlayed",value:function(){return this.get("played")}},{key:"getQualities",value:function(){return this.get("qualities")}},{key:"getQuality",value:function(){return this.get("quality")}},{key:"setQuality",value:function(e){return this.set("quality",e)}},{key:"getSeekable",value:function(){return this.get("seekable")}},{key:"getSeeking",value:function(){return this.get("seeking")}},{key:"getTextTracks",value:function(){return this.get("textTracks")}},{key:"getVideoEmbedCode",value:function(){return this.get("videoEmbedCode")}},{key:"getVideoId",value:function(){return this.get("videoId")}},{key:"getVideoTitle",value:function(){return this.get("videoTitle")}},{key:"getVideoWidth",value:function(){return this.get("videoWidth")}},{key:"getVideoHeight",value:function(){return this.get("videoHeight")}},{key:"getVideoUrl",value:function(){return this.get("videoUrl")}},{key:"getVolume",value:function(){return this.get("volume")}},{key:"setVolume",value:function(e){return this.set("volume",e)}}])&&r(e.prototype,t),n&&r(e,n),Player}();return e||(x=function(){for(var e,t=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],n=0,r=t.length,o={};n<r;n++)if((e=t[n])&&e[1]in document){for(n=0;n<e.length;n++)o[t[0][n]]=e[n];return o}return!1}(),C={fullscreenchange:x.fullscreenchange,fullscreenerror:x.fullscreenerror},j={request:function(o){return new Promise(function(e,t){function n(){j.off("fullscreenchange",n),e()}j.on("fullscreenchange",n);var r=(o=o||document.documentElement)[x.requestFullscreen]();r instanceof Promise&&r.then(n).catch(t)})},exit:function(){return new Promise(function(t,e){var n,r;j.isFullscreen?(n=function e(){j.off("fullscreenchange",e),t()},j.on("fullscreenchange",n),(r=document[x.exitFullscreen]())instanceof Promise&&r.then(n).catch(e)):t()})},on:function(e,t){var n=C[e];n&&document.addEventListener(n,t)},off:function(e,t){var n=C[e];n&&document.removeEventListener(n,t)}},Object.defineProperties(j,{isFullscreen:{get:function(){return Boolean(document[x.fullscreenElement])}},element:{enumerable:!0,get:function(){return document[x.fullscreenElement]}},isEnabled:{enumerable:!0,get:function(){return Boolean(document[x.fullscreenEnabled])}}}),q=j,function(e){function n(e){"console"in window&&console.error&&console.error("There was an error creating an embed: ".concat(e))}var t=0<arguments.length&&void 0!==e?e:document;[].slice.call(t.querySelectorAll("[data-vimeo-id], [data-vimeo-url]")).forEach(function(t){try{if(null!==t.getAttribute("data-vimeo-defer"))return;var e=_(t);F(s(e),e,t).then(function(e){return N(e,t)}).catch(n)}catch(e){n(e)}})}(),function(e){var r=0<arguments.length&&void 0!==e?e:document;window.VimeoPlayerResizeEmbeds_||(window.VimeoPlayerResizeEmbeds_=!0,window.addEventListener("message",function(e){if(c(e.origin)&&e.data&&"spacechange"===e.data.event)for(var t=r.querySelectorAll("iframe"),n=0;n<t.length;n++)if(t[n].contentWindow===e.source){t[n].parentElement.style.paddingBottom="".concat(e.data.data[0].bottom,"px");break}}
vendor: 11,908 bytes, lines 35242-35722
35242))}(),function(e){var u=0<arguments.length&&void 0!==e?e:document;window.VimeoSeoMetadataAppended||(window.VimeoSeoMetadataAppended=!0,window.addEventListener("message",function(e){if(c(e.origin)){var t=E(e.data);if(t&&"ready"===t.event)for(var n,r=u.querySelectorAll("iframe"),o=0;o<r.length;o++){var i=r[o],a=i.contentWindow===e.source;n=i.src,/^https:\/\/player\.vimeo\.com\/video\/\d+/.test(n)&&a&&new Player(i).callMethod("appendVideoMetadata",window.location.href)}}}))}()),Player});
35243
35244/**
35245 * Owl carousel
35246 * @version 2.0.0-beta.3
35247 * @author Bartosz Wojciechowski
35248 * @license The MIT License (MIT)
35249 * @todo Lazy Load Icon
35250 * @todo prevent animationend bubling
35251 * @todo itemsScaleUp
35252 * @todo Test Zepto
35253 * @todo stagePadding calculate wrong active classes
35254 */
35255;(function($, window, document, undefined) {
35256
35257	/**
35258	 * Creates a carousel.
35259	 * @class The Owl Carousel.
35260	 * @public
35261	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
35262	 * @param {Object} [options] - The options
35263	 */
35264	function Owl(element, options) {
35265
35266		/**
35267		 * Current settings for the carousel.
35268		 * @public
35269		 */
35270		this.settings = null;
35271
35272		/**
35273		 * Current options set by the caller including defaults.
35274		 * @public
35275		 */
35276		this.options = $.extend({}, Owl.Defaults, options);
35277
35278		/**
35279		 * Plugin element.
35280		 * @public
35281		 */
35282		this.$element = $(element);
35283
35284		/**
35285		 * Proxied event handlers.
35286		 * @protected
35287		 */
35288		this._handlers = {};
35289
35290		/**
35291		 * References to the running plugins of this carousel.
35292		 * @protected
35293		 */
35294		this._plugins = {};
35295
35296		/**
35297		 * Currently suppressed events to prevent them from beeing retriggered.
35298		 * @protected
35299		 */
35300		this._supress = {};
35301
35302		/**
35303		 * Absolute current position.
35304		 * @protected
35305		 */
35306		this._current = null;
35307
35308		/**
35309		 * Animation speed in milliseconds.
35310		 * @protected
35311		 */
35312		this._speed = null;
35313
35314		/**
35315		 * Coordinates of all items in pixel.
35316		 * @todo The name of this member is missleading.
35317		 * @protected
35318		 */
35319		this._coordinates = [];
35320
35321		/**
35322		 * Current breakpoint.
35323		 * @todo Real media queries would be nice.
35324		 * @protected
35325		 */
35326		this._breakpoint = null;
35327
35328		/**
35329		 * Current width of the plugin element.
35330		 */
35331		this._width = null;
35332
35333		/**
35334		 * All real items.
35335		 * @protected
35336		 */
35337		this._items = [];
35338
35339		/**
35340		 * All cloned items.
35341		 * @protected
35342		 */
35343		this._clones = [];
35344
35345		/**
35346		 * Merge values of all items.
35347		 * @todo Maybe this could be part of a plugin.
35348		 * @protected
35349		 */
35350		this._mergers = [];
35351
35352		/**
35353		 * Widths of all items.
35354		 */
35355		this._widths = [];
35356
35357		/**
35358		 * Invalidated parts within the update process.
35359		 * @protected
35360		 */
35361		this._invalidated = {};
35362
35363		/**
35364		 * Ordered list of workers for the update process.
35365		 * @protected
35366		 */
35367		this._pipe = [];
35368
35369		/**
35370		 * Current state information for the drag operation.
35371		 * @todo #261
35372		 * @protected
35373		 */
35374		this._drag = {
35375			time: null,
35376			target: null,
35377			pointer: null,
35378			stage: {
35379				start: null,
35380				current: null
35381			},
35382			direction: null
35383		};
35384
35385		/**
35386		 * Current state information and their tags.
35387		 * @type {Object}
35388		 * @protected
35389		 */
35390		this._states = {
35391			current: {},
35392			tags: {
35393				'initializing': [ 'busy' ],
35394				'animating': [ 'busy' ],
35395				'dragging': [ 'interacting' ]
35396			}
35397		};
35398
35399		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
35400			this._handlers[handler] = $.proxy(this[handler], this);
35401		}, this));
35402
35403		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
35404			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
35405				= new plugin(this);
35406		}, this));
35407
35408		$.each(Owl.Workers, $.proxy(function(priority, worker) {
35409			this._pipe.push({
35410				'filter': worker.filter,
35411				'run': $.proxy(worker.run, this)
35412			});
35413		}, this));
35414
35415		this.setup();
35416		this.initialize();
35417	}
35418
35419	/**
35420	 * Default options for the carousel.
35421	 * @public
35422	 */
35423	Owl.Defaults = {
35424		items: 3,
35425		loop: false,
35426		center: false,
35427		rewind: false,
35428
35429		mouseDrag: true,
35430		touchDrag: true,
35431		pullDrag: true,
35432		freeDrag: false,
35433
35434		margin: 0,
35435		stagePadding: 0,
35436
35437		merge: false,
35438		mergeFit: true,
35439		autoWidth: false,
35440
35441		startPosition: 0,
35442		rtl: false,
35443
35444		smartSpeed: 250,
35445		fluidSpeed: false,
35446		dragEndSpeed: false,
35447
35448		responsive: {},
35449		responsiveRefreshRate: 200,
35450		responsiveBaseElement: window,
35451
35452		fallbackEasing: 'swing',
35453
35454		info: false,
35455
35456		nestedItemSelector: false,
35457		itemSelector: false,
35458		itemElement: 'div',
35459		stageElement: 'div',
35460
35461		refreshClass: 'owl-refresh',
35462		loadedClass: 'owl-loaded',
35463		loadingClass: 'owl-loading',
35464		rtlClass: 'owl-rtl',
35465		responsiveClass: 'owl-responsive',
35466		dragClass: 'owl-drag',
35467		itemClass: 'owl-item',
35468		stageClass: 'owl-stage',
35469		stageOuterClass: 'owl-stage-outer',
35470		grabClass: 'owl-grab'
35471	};
35472
35473	/**
35474	 * Enumeration for width.
35475	 * @public
35476	 * @readonly
35477	 * @enum {String}
35478	 */
35479	Owl.Width = {
35480		Default: 'default',
35481		Inner: 'inner',
35482		Outer: 'outer'
35483	};
35484
35485	/**
35486	 * Enumeration for types.
35487	 * @public
35488	 * @readonly
35489	 * @enum {String}
35490	 */
35491	Owl.Type = {
35492		Event: 'event',
35493		State: 'state'
35494	};
35495
35496	/**
35497	 * Contains all registered plugins.
35498	 * @public
35499	 */
35500	Owl.Plugins = {};
35501
35502	/**
35503	 * List of workers involved in the update process.
35504	 */
35505	Owl.Workers = [ {
35506		filter: [ 'width', 'settings' ],
35507		run: function() {
35508			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
35509			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
35510		}
35511	}, {
35512		filter: [ 'width', 'items', 'settings' ],
35513		run: function(cache) {
35514			cache.current = this._items && this._items[this.relative(this._current)];
35515		}
35516	}, {
35517		filter: [ 'items', 'settings' ],
35518		run: function() {
35519			this.$stage.children('.cloned').remove();
35520		}
35521	}, {
35522		filter: [ 'width', 'items', 'settings' ],
35523		run: function(cache) {
35524			var margin = this.settings.margin || '',
35525				grid = !this.settings.autoWidth,
35526				rtl = this.settings.rtl,
35527				css = {
35528					'width': 'auto',
35529					'margin-left': rtl ? margin : '',
35530					'margin-right': rtl ? '' : margin
35531				};
35532
35533			!grid && this.$stage.children().css(css);
35534
35535			cache.css = css;
35536		}
35537	}, {
35538		filter: [ 'width', 'items', 'settings' ],
35539		run: function(cache) {
35540			//UNCODE edit to fix Chrome stage padding issue
35541			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
35542				merge = null,
35543				iterator = this._items.length,
35544				grid = !this.settings.autoWidth,
35545				widths = [];
35546
35547			cache.items = {
35548				merge: false,
35549				width: width
35550			};
35551
35552			while (iterator--) {
35553				merge = this._mergers[iterator];
35554				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
35555
35556				cache.items.merge = merge > 1 || cache.items.merge;
35557
35558				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
35559			}
35560
35561			this._widths = widths;
35562		}
35563	}, {
35564		filter: [ 'items', 'settings' ],
35565		run: function() {
35566			var clones = [],
35567				items = this._items,
35568				settings = this.settings,
35569				view = Math.max(settings.items * 2, 4),
35570				size = Math.ceil(items.length / 2) * 2,
35571				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
35572				append = '',
35573				prepend = '';
35574
35575			repeat /= 2;
35576
35577			while (repeat--) {
35578				clones.push(this.normalize(clones.length / 2, true));
35579				append = append + items[clones[clones.length - 1]][0].outerHTML;
35580				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
35581				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
35582			}
35583
35584			this._clones = clones;
35585
35586			// var appendVideo = $(append).find('.uncode-video-container');
35587			// if (appendVideo.length) {
35588			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
35589			// }
35590			// var prependVideo = $(prepend).find('.uncode-video-container');
35591			// if (prependVideo.length) {
35592			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
35593			// }
35594			$(append).addClass('cloned').appendTo(this.$stage);
35595			$(prepend).addClass('cloned').prependTo(this.$stage);
35596		}
35597	}, {
35598		filter: [ 'width', 'items', 'settings' ],
35599		run: function() {
35600			var rtl = this.settings.rtl ? 1 : -1,
35601				size = this._clones.length + this._items.length,
35602				iterator = -1,
35603				previous = 0,
35604				current = 0,
35605				coordinates = [];
35606
35607			while (++iterator < size) {
35608				previous = coordinates[iterator - 1] || 0;
35609				current = this._widths[this.relative(iterator)] + this.settings.margin;
35610				coordinates.push(previous + current * rtl);
35611			}
35612
35613			this._coordinates = coordinates;
35614		}
35615	}, {
35616		filter: [ 'width', 'items', 'settings' ],
35617		run: function() {
35618			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
35619				padding = stagePadding,
35620				coordinates = this._coordinates,
35621				css = {
35622					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
35623					'padding-left': padding || '',
35624					'padding-right': padding || ''
35625				};
35626
35627			this.$stage.css(css);
35628		}
35629	}, {
35630		filter: [ 'width', 'items', 'settings' ],
35631		run: function(cache) {
35632			var iterator = this._coordinates.length,
35633				grid = !this.settings.autoWidth,
35634				items = this.$stage.children();
35635
35636			if (grid && cache.items.merge) {
35637				while (iterator--) {
35638					cache.css.width = this._widths[this.relative(iterator)];
35639					items.eq(iterator).css(cache.css);
35640				}
35641			} else if (grid) {
35642				cache.css.width = cache.items.width;
35643				items.css(cache.css);
35644			}
35645		}
35646	}, {
35647		filter: [ 'items' ],
35648		run: function() {
35649			this._coordinates.length < 1 && this.$stage.removeAttr('style');
35650		}
35651	}, {
35652		filter: [ 'width', 'items', 'settings' ],
35653		run: function(cache) {
35654			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
35655			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
35656			this.reset(cache.current);
35657		}
35658	}, {
35659		filter: [ 'position' ],
35660		run: function() {
35661			this.animate(this.coordinates(this._current));
35662		}
35663	}, {
35664		filter: [ 'width', 'position', 'items', 'settings' ],
35665		run: function() {
35666			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
35667				rtl = this.settings.rtl ? 1 : -1,
35668				padding = this.settings.stagePadding * 2,
35669				begin = this.coordinates(this.current()) + padding,
35670				end = begin + this.width() * rtl,
35671				inner, outer, matches = [], i, n;
35672
35673			for (i = 0, n = this._coordinates.length; i < n; i++) {
35674				inner = this._coordinates[i - 1] || 0;
35675				outer = Math.abs(this._coordinates[i]) + padding * rtl;
35676
35677				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
35678					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
35679					matches.push(i);
35680				}
35681			}
35682
35683			this.$stage.children('.active').removeClass('active');
35684			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
35685
35686			if (this.settings.center) {
35687				this.$stage.children('.center').removeClass('center');
35688				this.$stage.children().eq(this.current()).addClass('center');
35689			}
35690		}
35691	} ];
35692
35693	/**
35694	 * Initializes the carousel.
35695	 * @protected
35696	 */
35697	Owl.prototype.initialize = function() {
35698		this.enter('initializing');
35699		this.trigger('initialize');
35700
35701		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
35702
35703		if (this.settings.autoWidth && !this.is('pre-loading')) {
35704			var imgs, nestedSelector, width;
35705			imgs = this.$element.find('img');
35706			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
35707			width = this.$element.children(nestedSelector).width();
35708
35709			if (imgs.length && width <= 0) {
35710				this.preloadAutoWidthImages(imgs);
35711			}
35712		}
35713
35714		this.$element.addClass(this.options.loadingClass);
35715
35716		// create stage
35717		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
35718			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
35719
35720		//UNCODE edit to exclude hidden items
35721		if ( this.settings.itemSelector ) {
35722			// append stage
35723			this.$element.prepend(this.$stage.parent());
35724			// append content
35725			this.replace(this.$element.find(' > ' + this.settings.itemSelector).not(this.$stage.parent()));
35726		} else {
35727			// append stage
35728			this.$element.append(this.$stage.parent());
35729			// append content
35730			this.replace(this.$element.children().not(this.$stage.parent()));
35731		}
35732
35733		// check visibility
35734		if (this.$element.is(':visible')) {
35735			// update view
35736			this.refresh();
35737		} else {
35738			// invalidate width
35739			this.invalidate('width');
35740		}
35741
35742		this.$element
35743			.removeClass(this.options.loadingClass)
35744			.addClass(this.options.loadedClass);
35745
35746		// register event handlers
35747		this.registerEventHandlers();
35748
35749		this.leave('initializing');
35750		this.trigger('initialized');
35751	};
35752
35753	/**
35754	 * Setups the current settings.
35755	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
35756	 * @todo Support for media queries by using `matchMedia` would be nice.
35757	 * @public
35758	 */
35759	Owl.prototype.setup = function() {
35760		var viewport = this.viewport(),
35761			overwrites = this.options.responsive,
35762			match = -1,
35763			settings = null;
35764
35765		if (!overwrites) {
35766			settings = $.extend({}, this.options);
35767		} else {
35768			$.each(overwrites, function(breakpoint) {
35769				if (breakpoint <= viewport && breakpoint > match) {
35770					match = Number(breakpoint);
35771				}
35772			});
35773
35774			settings = $.extend({}, this.options, overwrites[match]);
35775			delete settings.responsive;
35776
35777			// responsive class
35778			if (settings.responsiveClass) {
35779				this.$element.attr('class',
35780					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
35781				);
35782			}
35783		}
35784
35785		if (this.settings === null || this._breakpoint !== match) {
35786			this.trigger('change', { property: { name: 'settings', value: settings } });
35787			this._breakpoint = match;
35788			this.settings = settings;
35789			this.invalidate('settings');
35790			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
35791		}
35792	};
35793
35794	/**
35795	 * Updates option logic if necessery.
35796	 * @protected
35797	 */
35798	Owl.prototype.optionsLogic = function() {
35799		if (this.settings.autoWidth) {
35800			this.settings.stagePadding = false;
35801			this.settings.merge = false;
35802		}
35803	};
35804
35805	/**
35806	 * Prepares an item before add.
35807	 * @todo Rename event parameter `content` to `item`.
35808	 * @protected
35809	 * @returns {jQuery|HTMLElement} - The item container.
35810	 */
35811	Owl.prototype.prepare = function(item, index) {
35812		var event = this.trigger('prepare', { content: item });
35813		if (!event.data) {
35814			event.data = $('<' + this.settings.itemElement + '/>')
35815				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
35816		}
35817
35818		this.trigger('prepared', { content: event.data });
35819
35820		return event.data;
35821	};
35822
35823	/**
35824	 * Updates the view.
35825	 * @public
35826	 */
35827	Owl.prototype.update = function() {
35828		var i = 0,
35829			n = this._pipe.length,
35830			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
35831			cache = {};
35832
35833		while (i < n) {
35834			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
35835				this._pipe[i].run(cache);
35836			}
35837			i++;
35838		}
35839
35840		this._invalidated = {};
35841
35842		!this.is('valid') && this.enter('valid');
35843	};
35844
35845	/**
35846	 * Gets the width of the view.
35847	 * @public
35848	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
35849	 * @returns {Number} - The width of the view in pixel.
35850	 */
35851	Owl.prototype.width = function(dimension) {
35852		dimension = dimension || Owl.Width.Default;
35853		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
35854		switch (dimension) {
35855			case Owl.Width.Inner:
35856			case Owl.Width.Outer:
35857				return this._width;
35858			default:
35859				return this._width - stagePadding * 2 + this.settings.margin;
35860		}
35861	};
35862
35863	/**
35864	 * Refreshes the carousel primarily for adaptive purposes.
35865	 * @public
35866	 */
35867	Owl.prototype.refresh = function() {
35868		this.enter('refreshing');
35869		this.trigger('refresh');
35870
35871		this.setup();
35872
35873		this.optionsLogic();
35874
35875		this.$element.addClass(this.options.refreshClass);
35876
35877		this.update();
35878
35879		this.$element.removeClass(this.options.refreshClass);
35880
35881		this.leave('refreshing');
35882		this.trigger('refreshed');
35883	};
35884
35885	/**
35886	 * Checks window `resize` event.
35887	 * @protected
35888	 */
35889	Owl.prototype.onThrottledResize = function() {
35890		window.clearTimeout(this.resizeTimer);
35891		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
35892	};
35893
35894	/**
35895	 * Checks window `resize` event.
35896	 * @protected
35897	 */
35898	Owl.prototype.onResize = function() {
35899		if (!this._items.length) {
35900			return false;
vendor: 46,301 bytes, lines 35901-37605
35901		}
35902
35903		if (this._width === this.$element.width()) {
35904			return false;
35905		}
35906
35907		if (!this.$element.is(':visible')) {
35908			return false;
35909		}
35910
35911		this.enter('resizing');
35912
35913		if (this.trigger('resize').isDefaultPrevented()) {
35914			this.leave('resizing');
35915			return false;
35916		}
35917
35918		this.invalidate('width');
35919
35920		this.refresh();
35921
35922		this.leave('resizing');
35923		this.trigger('resized');
35924	};
35925
35926	/**
35927	 * Registers event handlers.
35928	 * @todo Check `msPointerEnabled`
35929	 * @todo #261
35930	 * @protected
35931	 */
35932	Owl.prototype.registerEventHandlers = function() {
35933		if ($.support.transition) {
35934			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
35935		}
35936
35937		if (this.settings.responsive !== false) {
35938			this.on(window, 'resize', this._handlers.onThrottledResize);
35939		}
35940
35941		if (this.settings.mouseDrag) {
35942			this.$element.addClass(this.options.dragClass);
35943			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
35944			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
35945		}
35946
35947		if (this.settings.touchDrag){
35948			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
35949			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
35950		}
35951	};
35952
35953	/**
35954	 * Handles `touchstart` and `mousedown` events.
35955	 * @todo Horizontal swipe threshold as option
35956	 * @todo #261
35957	 * @protected
35958	 * @param {Event} event - The event arguments.
35959	 */
35960	Owl.prototype.onDragStart = function(event) {
35961		var stage = null;
35962
35963		if (event.which === 3) {
35964			return;
35965		}
35966
35967		if ($.support.transform) {
35968			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
35969			stage = {
35970				x: stage[stage.length === 16 ? 12 : 4],
35971				y: stage[stage.length === 16 ? 13 : 5]
35972			};
35973		} else {
35974			stage = this.$stage.position();
35975			stage = {
35976				x: this.settings.rtl ?
35977					stage.left + this.$stage.width() - this.width() + this.settings.margin :
35978					stage.left,
35979				y: stage.top
35980			};
35981		}
35982
35983		if (this.is('animating')) {
35984			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
35985			this.invalidate('position');
35986		}
35987
35988		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
35989
35990		this.speed(0);
35991
35992		this._drag.time = new Date().getTime();
35993		this._drag.target = $(event.target);
35994		this._drag.stage.start = stage;
35995		this._drag.stage.current = stage;
35996		this._drag.pointer = this.pointer(event);
35997
35998		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
35999
36000		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
36001			var delta = this.difference(this._drag.pointer, this.pointer(event));
36002
36003			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
36004
36005			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
36006				return;
36007			}
36008
36009			event.preventDefault();
36010
36011			this.enter('dragging');
36012			this.trigger('drag');
36013		}, this));
36014	};
36015
36016	/**
36017	 * Handles the `touchmove` and `mousemove` events.
36018	 * @todo #261
36019	 * @protected
36020	 * @param {Event} event - The event arguments.
36021	 */
36022	Owl.prototype.onDragMove = function(event) {
36023		var minimum = null,
36024			maximum = null,
36025			pull = null,
36026			delta = this.difference(this._drag.pointer, this.pointer(event)),
36027			stage = this.difference(this._drag.stage.start, delta);
36028
36029		if (!this.is('dragging')) {
36030			return;
36031		}
36032
36033		event.preventDefault();
36034
36035		if (this.settings.loop) {
36036			minimum = this.coordinates(this.minimum());
36037			maximum = this.coordinates(this.maximum() + 1) - minimum;
36038			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
36039		} else {
36040			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
36041			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
36042			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
36043			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
36044		}
36045
36046		this._drag.stage.current = stage;
36047
36048		this.animate(stage.x);
36049	};
36050
36051	/**
36052	 * Handles the `touchend` and `mouseup` events.
36053	 * @todo #261
36054	 * @todo Threshold for click event
36055	 * @protected
36056	 * @param {Event} event - The event arguments.
36057	 */
36058	Owl.prototype.onDragEnd = function(event) {
36059		var delta = this.difference(this._drag.pointer, this.pointer(event)),
36060			stage = this._drag.stage.current,
36061			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
36062
36063		$(document).off('.owl.core');
36064
36065		this.$element.removeClass(this.options.grabClass);
36066
36067		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
36068			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
36069			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
36070			this.invalidate('position');
36071			this.update();
36072
36073			this._drag.direction = direction;
36074
36075			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
36076				this._drag.target.one('click.owl.core', function() { return false; });
36077			}
36078		}
36079
36080		if (!this.is('dragging')) {
36081			return;
36082		}
36083
36084		this.leave('dragging');
36085		this.trigger('dragged');
36086	};
36087
36088	/**
36089	 * Gets absolute position of the closest item for a coordinate.
36090	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
36091	 * @protected
36092	 * @param {Number} coordinate - The coordinate in pixel.
36093	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
36094	 * @return {Number} - The absolute position of the closest item.
36095	 */
36096	Owl.prototype.closest = function(coordinate, direction) {
36097		var position = -1,
36098			pull = 30,
36099			width = this.width(),
36100			coordinates = this.coordinates();
36101
36102		if (!this.settings.freeDrag) {
36103			// check closest item
36104			$.each(coordinates, $.proxy(function(index, value) {
36105				if (coordinate > value - pull && coordinate < value + pull) {
36106					position = index;
36107				} else if (this.op(coordinate, '<', value)
36108					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
36109					position = direction === 'left' ? index + 1 : index;
36110				}
36111				return position === -1;
36112			}, this));
36113		}
36114
36115		if (!this.settings.loop) {
36116			// non loop boundries
36117			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
36118				position = coordinate = this.minimum();
36119			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
36120				position = coordinate = this.maximum();
36121			}
36122		}
36123
36124		return position;
36125	};
36126
36127	/**
36128	 * Animates the stage.
36129	 * @todo #270
36130	 * @public
36131	 * @param {Number} coordinate - The coordinate in pixels.
36132	 */
36133	Owl.prototype.animate = function(coordinate) {
36134		var animate = this.speed() > 0;
36135
36136		this.is('animating') && this.onTransitionEnd();
36137
36138		if (animate) {
36139			this.enter('animating');
36140			this.trigger('translate');
36141		}
36142
36143		if ($.support.transform3d && $.support.transition) {
36144			this.$stage.css({
36145				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
36146				transition: (this.speed() / 1000) + 's'
36147			});
36148		} else if (animate) {
36149			this.$stage.animate({
36150				left: coordinate + 'px'
36151			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
36152		} else {
36153			this.$stage.css({
36154				left: coordinate + 'px'
36155			});
36156		}
36157	};
36158
36159	/**
36160	 * Checks whether the carousel is in a specific state or not.
36161	 * @param {String} state - The state to check.
36162	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
36163	 */
36164	Owl.prototype.is = function(state) {
36165		return this._states.current[state] && this._states.current[state] > 0;
36166	};
36167
36168	/**
36169	 * Sets the absolute position of the current item.
36170	 * @public
36171	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
36172	 * @returns {Number} - The absolute position of the current item.
36173	 */
36174	Owl.prototype.current = function(position) {
36175		if (position === undefined) {
36176			return this._current;
36177		}
36178
36179		if (this._items.length === 0) {
36180			return undefined;
36181		}
36182
36183		position = this.normalize(position);
36184
36185		if (this._current !== position) {
36186			var event = this.trigger('change', { property: { name: 'position', value: position } });
36187
36188			if (event.data !== undefined) {
36189				position = this.normalize(event.data);
36190			}
36191
36192			this._current = position;
36193
36194			this.invalidate('position');
36195
36196			this.trigger('changed', { property: { name: 'position', value: this._current } });
36197		}
36198
36199		return this._current;
36200	};
36201
36202	/**
36203	 * Invalidates the given part of the update routine.
36204	 * @param {String} [part] - The part to invalidate.
36205	 * @returns {Array.<String>} - The invalidated parts.
36206	 */
36207	Owl.prototype.invalidate = function(part) {
36208		if ($.type(part) === 'string') {
36209			this._invalidated[part] = true;
36210			this.is('valid') && this.leave('valid');
36211		}
36212		return $.map(this._invalidated, function(v, i) { return i });
36213	};
36214
36215	/**
36216	 * Resets the absolute position of the current item.
36217	 * @public
36218	 * @param {Number} position - The absolute position of the new item.
36219	 */
36220	Owl.prototype.reset = function(position) {
36221		position = this.normalize(position);
36222
36223		if (position === undefined) {
36224			return;
36225		}
36226
36227		this._speed = 0;
36228		this._current = position;
36229
36230		this.suppress([ 'translate', 'translated' ]);
36231
36232		this.animate(this.coordinates(position));
36233
36234		this.release([ 'translate', 'translated' ]);
36235	};
36236
36237	/**
36238	 * Normalizes an absolute or a relative position of an item.
36239	 * @public
36240	 * @param {Number} position - The absolute or relative position to normalize.
36241	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
36242	 * @returns {Number} - The normalized position.
36243	 */
36244	Owl.prototype.normalize = function(position, relative) {
36245		var n = this._items.length,
36246			m = relative ? 0 : this._clones.length;
36247
36248		if (!$.isNumeric(position) || n < 1) {
36249			position = undefined;
36250		} else if (position < 0 || position >= n + m) {
36251			position = ((position - m / 2) % n + n) % n + m / 2;
36252		}
36253
36254		return position;
36255	};
36256
36257	/**
36258	 * Converts an absolute position of an item into a relative one.
36259	 * @public
36260	 * @param {Number} position - The absolute position to convert.
36261	 * @returns {Number} - The converted position.
36262	 */
36263	Owl.prototype.relative = function(position) {
36264		position -= this._clones.length / 2;
36265		return this.normalize(position, true);
36266	};
36267
36268	/**
36269	 * Gets the maximum position for the current item.
36270	 * @public
36271	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
36272	 * @returns {Number}
36273	 */
36274	Owl.prototype.maximum = function(relative) {
36275		var settings = this.settings,
36276			maximum = this._coordinates.length,
36277			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
36278			i = -1, j;
36279
36280		if (settings.loop) {
36281			maximum = this._clones.length / 2 + this._items.length - 1;
36282		} else if (settings.autoWidth || settings.merge) {
36283			// binary search
36284			while (maximum - i > 1) {
36285				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
36286					? i = j : maximum = j;
36287			}
36288		} else if (settings.center) {
36289			maximum = this._items.length - 1;
36290		} else {
36291			maximum = this._items.length - settings.items;
36292		}
36293
36294		if (relative) {
36295			maximum -= this._clones.length / 2;
36296		}
36297
36298		return Math.max(maximum, 0);
36299	};
36300
36301	/**
36302	 * Gets the minimum position for the current item.
36303	 * @public
36304	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
36305	 * @returns {Number}
36306	 */
36307	Owl.prototype.minimum = function(relative) {
36308		return relative ? 0 : this._clones.length / 2;
36309	};
36310
36311	/**
36312	 * Gets an item at the specified relative position.
36313	 * @public
36314	 * @param {Number} [position] - The relative position of the item.
36315	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
36316	 */
36317	Owl.prototype.items = function(position) {
36318		if (position === undefined) {
36319			return this._items.slice();
36320		}
36321
36322		position = this.normalize(position, true);
36323		return this._items[position];
36324	};
36325
36326	/**
36327	 * Gets an item at the specified relative position.
36328	 * @public
36329	 * @param {Number} [position] - The relative position of the item.
36330	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
36331	 */
36332	Owl.prototype.mergers = function(position) {
36333		if (position === undefined) {
36334			return this._mergers.slice();
36335		}
36336
36337		position = this.normalize(position, true);
36338		return this._mergers[position];
36339	};
36340
36341	/**
36342	 * Gets the absolute positions of clones for an item.
36343	 * @public
36344	 * @param {Number} [position] - The relative position of the item.
36345	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
36346	 */
36347	Owl.prototype.clones = function(position) {
36348		var odd = this._clones.length / 2,
36349			even = odd + this._items.length,
36350			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
36351
36352		if (position === undefined) {
36353			return $.map(this._clones, function(v, i) { return map(i) });
36354		}
36355
36356		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
36357	};
36358
36359	/**
36360	 * Sets the current animation speed.
36361	 * @public
36362	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
36363	 * @returns {Number} - The current animation speed in milliseconds.
36364	 */
36365	Owl.prototype.speed = function(speed) {
36366		if (speed !== undefined) {
36367			this._speed = speed;
36368		}
36369
36370		return this._speed;
36371	};
36372
36373	/**
36374	 * Gets the coordinate of an item.
36375	 * @todo The name of this method is missleanding.
36376	 * @public
36377	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
36378	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
36379	 */
36380	Owl.prototype.coordinates = function(position) {
36381		var coordinate = null;
36382
36383		if (position === undefined) {
36384			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
36385				return this.coordinates(index);
36386			}, this));
36387		}
36388
36389		if (this.settings.center) {
36390			coordinate = this._coordinates[position];
36391			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
36392		} else {
36393			coordinate = this._coordinates[position - 1] || 0;
36394		}
36395
36396		return coordinate;
36397	};
36398
36399	/**
36400	 * Calculates the speed for a translation.
36401	 * @protected
36402	 * @param {Number} from - The absolute position of the start item.
36403	 * @param {Number} to - The absolute position of the target item.
36404	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
36405	 * @returns {Number} - The time in milliseconds for the translation.
36406	 */
36407	Owl.prototype.duration = function(from, to, factor) {
36408		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
36409	};
36410
36411	/**
36412	 * Slides to the specified item.
36413	 * @public
36414	 * @param {Number} position - The position of the item.
36415	 * @param {Number} [speed] - The time in milliseconds for the transition.
36416	 */
36417	Owl.prototype.to = function(position, speed) {
36418		var current = this.current(),
36419			revert = null,
36420			distance = position - this.relative(current),
36421			direction = (distance > 0) - (distance < 0),
36422			items = this._items.length,
36423			minimum = this.minimum(),
36424			maximum = this.maximum();
36425
36426		if (this.settings.loop) {
36427			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
36428				distance += direction * -1 * items;
36429			}
36430
36431			position = current + distance;
36432			revert = ((position - minimum) % items + items) % items + minimum;
36433
36434			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
36435				current = revert - distance;
36436				position = revert;
36437				this.reset(current);
36438			}
36439		} else if (this.settings.rewind) {
36440			maximum += 1;
36441			position = (position % maximum + maximum) % maximum;
36442		} else {
36443			position = Math.max(minimum, Math.min(maximum, position));
36444		}
36445
36446		this.speed(this.duration(current, position, speed));
36447		this.current(position);
36448
36449		if (this.$element.is(':visible')) {
36450			this.update();
36451		}
36452	};
36453
36454	/**
36455	 * Slides to the next item.
36456	 * @public
36457	 * @param {Number} [speed] - The time in milliseconds for the transition.
36458	 */
36459	Owl.prototype.next = function(speed) {
36460		speed = speed || false;
36461		this.to(this.relative(this.current()) + 1, speed);
36462	};
36463
36464	/**
36465	 * Slides to the previous item.
36466	 * @public
36467	 * @param {Number} [speed] - The time in milliseconds for the transition.
36468	 */
36469	Owl.prototype.prev = function(speed) {
36470		speed = speed || false;
36471		this.to(this.relative(this.current()) - 1, speed);
36472	};
36473
36474	/**
36475	 * Handles the end of an animation.
36476	 * @protected
36477	 * @param {Event} event - The event arguments.
36478	 */
36479	Owl.prototype.onTransitionEnd = function(event) {
36480
36481		// if css2 animation then event object is undefined
36482		if (event !== undefined) {
36483			event.stopPropagation();
36484
36485			// Catch only owl-stage transitionEnd event
36486			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
36487				return false;
36488			}
36489		}
36490
36491		this.leave('animating');
36492		this.trigger('translated');
36493	};
36494
36495	/**
36496	 * Gets viewport width.
36497	 * @protected
36498	 * @return {Number} - The width in pixel.
36499	 */
36500	Owl.prototype.viewport = function() {
36501		var width;
36502		if (this.options.responsiveBaseElement !== window) {
36503			width = $(this.options.responsiveBaseElement).width();
36504		} else if (window.innerWidth) {
36505			width = window.innerWidth;
36506		} else if (document.documentElement && document.documentElement.clientWidth) {
36507			width = document.documentElement.clientWidth;
36508		} else {
36509			throw 'Can not detect viewport width.';
36510		}
36511
36512		return width;
36513	};
36514
36515	/**
36516	 * Replaces the current content.
36517	 * @public
36518	 * @param {HTMLElement|jQuery|String} content - The new content.
36519	 */
36520	Owl.prototype.replace = function(content) {
36521		this.$stage.empty();
36522		this._items = [];
36523
36524		if (content) {
36525			content = (content instanceof jQuery) ? content : $(content);
36526		}
36527
36528		if (this.settings.nestedItemSelector) {
36529			content = content.find('.' + this.settings.nestedItemSelector);
36530		}
36531
36532		content.filter(function() {
36533			return this.nodeType === 1;
36534		}).each($.proxy(function(index, item) {
36535			item = this.prepare(item, index);
36536			this.$stage.append(item);
36537			this._items.push(item);
36538			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
36539		}, this));
36540
36541		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
36542
36543		this.invalidate('items');
36544	};
36545
36546	/**
36547	 * Adds an item.
36548	 * @todo Use `item` instead of `content` for the event arguments.
36549	 * @public
36550	 * @param {HTMLElement|jQuery|String} content - The item content to add.
36551	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
36552	 */
36553	Owl.prototype.add = function(content, position) {
36554		var current = this.relative(this._current);
36555
36556		position = position === undefined ? this._items.length : this.normalize(position, true);
36557		content = content instanceof jQuery ? content : $(content);
36558
36559		this.trigger('add', { content: content, position: position });
36560
36561		content = this.prepare(content, this._items[current].index());
36562
36563		if (this._items.length === 0 || position === this._items.length) {
36564			this._items.length === 0 && this.$stage.append(content);
36565			this._items.length !== 0 && this._items[position - 1].after(content);
36566			this._items.push(content);
36567			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
36568		} else {
36569			this._items[position].before(content);
36570			this._items.splice(position, 0, content);
36571			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
36572		}
36573
36574		this._items[current] && this.reset(this._items[current].index());
36575
36576		this.invalidate('items');
36577
36578		this.trigger('added', { content: content, position: position });
36579	};
36580
36581	/**
36582	 * Removes an item by its position.
36583	 * @todo Use `item` instead of `content` for the event arguments.
36584	 * @public
36585	 * @param {Number} position - The relative position of the item to remove.
36586	 */
36587	Owl.prototype.remove = function(position) {
36588		position = this.normalize(position, true);
36589
36590		if (position === undefined) {
36591			return;
36592		}
36593
36594		this.trigger('remove', { content: this._items[position], position: position });
36595
36596		this._items[position].remove();
36597		this._items.splice(position, 1);
36598		this._mergers.splice(position, 1);
36599
36600		this.invalidate('items');
36601
36602		this.trigger('removed', { content: null, position: position });
36603	};
36604
36605	/**
36606	 * Preloads images with auto width.
36607	 * @todo Replace by a more generic approach
36608	 * @protected
36609	 */
36610	Owl.prototype.preloadAutoWidthImages = function(images) {
36611		images.each($.proxy(function(i, element) {
36612			this.enter('pre-loading');
36613			element = $(element);
36614			$(new Image()).one('load', $.proxy(function(e) {
36615				element.attr('src', e.target.src);
36616				element.css('opacity', 1);
36617				this.leave('pre-loading');
36618				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
36619			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
36620		}, this));
36621	};
36622
36623	/**
36624	 * Destroys the carousel.
36625	 * @public
36626	 */
36627	Owl.prototype.destroy = function() {
36628
36629		this.$element.off('.owl.core');
36630		this.$stage.off('.owl.core');
36631		$(document).off('.owl.core');
36632
36633		if (this.settings.responsive !== false) {
36634			window.clearTimeout(this.resizeTimer);
36635			this.off(window, 'resize', this._handlers.onThrottledResize);
36636		}
36637
36638		for (var i in this._plugins) {
36639			this._plugins[i].destroy();
36640		}
36641
36642		this.$stage.children('.cloned').remove();
36643
36644		this.$stage.unwrap();
36645		this.$stage.children().contents().unwrap();
36646		this.$stage.children().unwrap();
36647
36648		this.$element
36649			.removeClass(this.options.refreshClass)
36650			.removeClass(this.options.loadingClass)
36651			.removeClass(this.options.loadedClass)
36652			.removeClass(this.options.rtlClass)
36653			.removeClass(this.options.dragClass)
36654			.removeClass(this.options.grabClass)
36655			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
36656			.removeData('owl.carousel');
36657	};
36658
36659	/**
36660	 * Operators to calculate right-to-left and left-to-right.
36661	 * @protected
36662	 * @param {Number} [a] - The left side operand.
36663	 * @param {String} [o] - The operator.
36664	 * @param {Number} [b] - The right side operand.
36665	 */
36666	Owl.prototype.op = function(a, o, b) {
36667		var rtl = this.settings.rtl;
36668		switch (o) {
36669			case '<':
36670				return rtl ? a > b : a < b;
36671			case '>':
36672				return rtl ? a < b : a > b;
36673			case '>=':
36674				return rtl ? a <= b : a >= b;
36675			case '<=':
36676				return rtl ? a >= b : a <= b;
36677			default:
36678				break;
36679		}
36680	};
36681
36682	/**
36683	 * Attaches to an internal event.
36684	 * @protected
36685	 * @param {HTMLElement} element - The event source.
36686	 * @param {String} event - The event name.
36687	 * @param {Function} listener - The event handler to attach.
36688	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
36689	 */
36690	Owl.prototype.on = function(element, event, listener, capture) {
36691		if (element.addEventListener) {
36692			element.addEventListener(event, listener, capture);
36693		} else if (element.attachEvent) {
36694			element.attachEvent('on' + event, listener);
36695		}
36696	};
36697
36698	/**
36699	 * Detaches from an internal event.
36700	 * @protected
36701	 * @param {HTMLElement} element - The event source.
36702	 * @param {String} event - The event name.
36703	 * @param {Function} listener - The attached event handler to detach.
36704	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
36705	 */
36706	Owl.prototype.off = function(element, event, listener, capture) {
36707		if (element.removeEventListener) {
36708			element.removeEventListener(event, listener, capture);
36709		} else if (element.detachEvent) {
36710			element.detachEvent('on' + event, listener);
36711		}
36712	};
36713
36714	/**
36715	 * Triggers a public event.
36716	 * @todo Remove `status`, `relatedTarget` should be used instead.
36717	 * @protected
36718	 * @param {String} name - The event name.
36719	 * @param {*} [data=null] - The event data.
36720	 * @param {String} [namespace=carousel] - The event namespace.
36721	 * @param {String} [state] - The state which is associated with the event.
36722	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
36723	 * @returns {Event} - The event arguments.
36724	 */
36725	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
36726		var status = {
36727			item: { count: this._items.length, index: this.current() }
36728		}, handler = $.camelCase(
36729			$.grep([ 'on', name, namespace ], function(v) { return v })
36730				.join('-').toLowerCase()
36731		), event = $.Event(
36732			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
36733			$.extend({ relatedTarget: this }, status, data)
36734		);
36735
36736		if (!this._supress[name]) {
36737			$.each(this._plugins, function(name, plugin) {
36738				if (plugin.onTrigger) {
36739					plugin.onTrigger(event);
36740				}
36741			});
36742
36743			this.register({ type: Owl.Type.Event, name: name });
36744			this.$element.trigger(event);
36745
36746			if (this.settings && typeof this.settings[handler] === 'function') {
36747				this.settings[handler].call(this, event);
36748			}
36749		}
36750
36751		return event;
36752	};
36753
36754	/**
36755	 * Enters a state.
36756	 * @param name - The state name.
36757	 */
36758	Owl.prototype.enter = function(name) {
36759		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
36760			if (this._states.current[name] === undefined) {
36761				this._states.current[name] = 0;
36762			}
36763
36764			this._states.current[name]++;
36765		}, this));
36766	};
36767
36768	/**
36769	 * Leaves a state.
36770	 * @param name - The state name.
36771	 */
36772	Owl.prototype.leave = function(name) {
36773		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
36774			this._states.current[name]--;
36775		}, this));
36776	};
36777
36778	/**
36779	 * Registers an event or state.
36780	 * @public
36781	 * @param {Object} object - The event or state to register.
36782	 */
36783	Owl.prototype.register = function(object) {
36784		if (object.type === Owl.Type.Event) {
36785			if (!$.event.special[object.name]) {
36786				$.event.special[object.name] = {};
36787			}
36788
36789			if (!$.event.special[object.name].owl) {
36790				var _default = $.event.special[object.name]._default;
36791				$.event.special[object.name]._default = function(e) {
36792					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
36793						return _default.apply(this, arguments);
36794					}
36795					return e.namespace && e.namespace.indexOf('owl') > -1;
36796				};
36797				$.event.special[object.name].owl = true;
36798			}
36799		} else if (object.type === Owl.Type.State) {
36800			if (!this._states.tags[object.name]) {
36801				this._states.tags[object.name] = object.tags;
36802			} else {
36803				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
36804			}
36805
36806			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
36807				return $.inArray(tag, this._states.tags[object.name]) === i;
36808			}, this));
36809		}
36810	};
36811
36812	/**
36813	 * Suppresses events.
36814	 * @protected
36815	 * @param {Array.<String>} events - The events to suppress.
36816	 */
36817	Owl.prototype.suppress = function(events) {
36818		$.each(events, $.proxy(function(index, event) {
36819			this._supress[event] = true;
36820		}, this));
36821	};
36822
36823	/**
36824	 * Releases suppressed events.
36825	 * @protected
36826	 * @param {Array.<String>} events - The events to release.
36827	 */
36828	Owl.prototype.release = function(events) {
36829		$.each(events, $.proxy(function(index, event) {
36830			delete this._supress[event];
36831		}, this));
36832	};
36833
36834	/**
36835	 * Gets unified pointer coordinates from event.
36836	 * @todo #261
36837	 * @protected
36838	 * @param {Event} - The `mousedown` or `touchstart` event.
36839	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
36840	 */
36841	Owl.prototype.pointer = function(event) {
36842		var result = { x: null, y: null };
36843
36844		event = event.originalEvent || event || window.event;
36845
36846		event = event.touches && event.touches.length ?
36847			event.touches[0] : event.changedTouches && event.changedTouches.length ?
36848				event.changedTouches[0] : event;
36849
36850		if (event.pageX) {
36851			result.x = event.pageX;
36852			result.y = event.pageY;
36853		} else {
36854			result.x = event.clientX;
36855			result.y = event.clientY;
36856		}
36857
36858		return result;
36859	};
36860
36861	/**
36862	 * Gets the difference of two vectors.
36863	 * @todo #261
36864	 * @protected
36865	 * @param {Object} - The first vector.
36866	 * @param {Object} - The second vector.
36867	 * @returns {Object} - The difference.
36868	 */
36869	Owl.prototype.difference = function(first, second) {
36870		return {
36871			x: first.x - second.x,
36872			y: first.y - second.y
36873		};
36874	};
36875
36876	/**
36877	 * The jQuery Plugin for the Owl Carousel
36878	 * @todo Navigation plugin `next` and `prev`
36879	 * @public
36880	 */
36881	$.fn.owlCarousel = function(option) {
36882		var args = Array.prototype.slice.call(arguments, 1);
36883
36884		return this.each(function() {
36885			var $this = $(this),
36886				data = $this.data('owl.carousel');
36887
36888			if (!data) {
36889				data = new Owl(this, typeof option == 'object' && option);
36890				$this.data('owl.carousel', data);
36891
36892				$.each([
36893					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
36894				], function(i, event) {
36895					data.register({ type: Owl.Type.Event, name: event });
36896					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
36897						if (e.namespace && e.relatedTarget !== this) {
36898							this.suppress([ event ]);
36899							data[event].apply(this, [].slice.call(arguments, 1));
36900							this.release([ event ]);
36901						}
36902					}, data));
36903				});
36904			}
36905
36906			if (typeof option == 'string' && option.charAt(0) !== '_') {
36907				data[option].apply(data, args);
36908			}
36909		});
36910	};
36911
36912	/**
36913	 * The constructor for the jQuery Plugin
36914	 * @public
36915	 */
36916	$.fn.owlCarousel.Constructor = Owl;
36917
36918})(window.Zepto || window.jQuery, window, document);
36919
36920/**
36921 * AutoRefresh Plugin
36922 * @version 2.0.0-beta.3
36923 * @author Artus Kolanowski
36924 * @license The MIT License (MIT)
36925 */
36926;(function($, window, document, undefined) {
36927
36928	/**
36929	 * Creates the auto refresh plugin.
36930	 * @class The Auto Refresh Plugin
36931	 * @param {Owl} carousel - The Owl Carousel
36932	 */
36933	var AutoRefresh = function(carousel) {
36934		/**
36935		 * Reference to the core.
36936		 * @protected
36937		 * @type {Owl}
36938		 */
36939		this._core = carousel;
36940
36941		/**
36942		 * Refresh interval.
36943		 * @protected
36944		 * @type {number}
36945		 */
36946		this._interval = null;
36947
36948		/**
36949		 * Whether the element is currently visible or not.
36950		 * @protected
36951		 * @type {Boolean}
36952		 */
36953		this._visible = null;
36954
36955		/**
36956		 * All event handlers.
36957		 * @protected
36958		 * @type {Object}
36959		 */
36960		this._handlers = {
36961			'initialized.owl.carousel': $.proxy(function(e) {
36962				if (e.namespace && this._core.settings.autoRefresh) {
36963					this.watch();
36964				}
36965			}, this)
36966		};
36967
36968		// set default options
36969		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
36970
36971		// register event handlers
36972		this._core.$element.on(this._handlers);
36973	};
36974
36975	/**
36976	 * Default options.
36977	 * @public
36978	 */
36979	AutoRefresh.Defaults = {
36980		autoRefresh: true,
36981		autoRefreshInterval: 500
36982	};
36983
36984	/**
36985	 * Watches the element.
36986	 */
36987	AutoRefresh.prototype.watch = function() {
36988		if (this._interval) {
36989			return;
36990		}
36991
36992		this._visible = this._core.$element.is(':visible');
36993		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
36994	};
36995
36996	/**
36997	 * Refreshes the element.
36998	 */
36999	AutoRefresh.prototype.refresh = function() {
37000		if (this._core.$element.is(':visible') === this._visible || this._core.$element.closest('.drop-menu').length) {
37001			return;
37002		}
37003
37004		this._visible = !this._visible;
37005
37006		this._core.$element.toggleClass('owl-hidden', !this._visible);
37007
37008		this._visible && (this._core.invalidate('width') && this._core.refresh());
37009	};
37010
37011	/**
37012	 * Destroys the plugin.
37013	 */
37014	AutoRefresh.prototype.destroy = function() {
37015		var handler, property;
37016
37017		window.clearInterval(this._interval);
37018
37019		for (handler in this._handlers) {
37020			this._core.$element.off(handler, this._handlers[handler]);
37021		}
37022		for (property in Object.getOwnPropertyNames(this)) {
37023			typeof this[property] != 'function' && (this[property] = null);
37024		}
37025	};
37026
37027	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
37028
37029})(window.Zepto || window.jQuery, window, document);
37030
37031/**
37032 * Lazy Plugin
37033 * @version 2.0.0-beta.3
37034 * @author Bartosz Wojciechowski
37035 * @license The MIT License (MIT)
37036 */
37037;(function($, window, document, undefined) {
37038
37039	/**
37040	 * Creates the lazy plugin.
37041	 * @class The Lazy Plugin
37042	 * @param {Owl} carousel - The Owl Carousel
37043	 */
37044	var Lazy = function(carousel) {
37045
37046		/**
37047		 * Reference to the core.
37048		 * @protected
37049		 * @type {Owl}
37050		 */
37051		this._core = carousel;
37052
37053		/**
37054		 * Already loaded items.
37055		 * @protected
37056		 * @type {Array.<jQuery>}
37057		 */
37058		this._loaded = [];
37059
37060		/**
37061		 * Event handlers.
37062		 * @protected
37063		 * @type {Object}
37064		 */
37065		this._handlers = {
37066			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
37067				if (!e.namespace) {
37068					return;
37069				}
37070
37071				if (!this._core.settings || !this._core.settings.lazyLoad) {
37072					return;
37073				}
37074
37075				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
37076					var settings = this._core.settings,
37077						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
37078						i = ((settings.center && n * -1) || 0),
37079						position = ((e.property && e.property.value) || this._core.current()) + i,
37080						clones = this._core.clones().length,
37081						load = $.proxy(function(i, v) { this.load(v) }, this);
37082
37083					while (i++ < n) {
37084						this.load(clones / 2 + this._core.relative(position));
37085						clones && $.each(this._core.clones(this._core.relative(position)), load);
37086						position++;
37087					}
37088				}
37089			}, this)
37090		};
37091
37092		// set the default options
37093		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
37094
37095		// register event handler
37096		this._core.$element.on(this._handlers);
37097	}
37098
37099	/**
37100	 * Default options.
37101	 * @public
37102	 */
37103	Lazy.Defaults = {
37104		lazyLoad: false
37105	}
37106
37107	/**
37108	 * Loads all resources of an item at the specified position.
37109	 * @param {Number} position - The absolute position of the item.
37110	 * @protected
37111	 */
37112	Lazy.prototype.load = function(position) {
37113		var $item = this._core.$stage.children().eq(position),
37114			$elements = $item && $item.find('.owl-lazy');
37115
37116		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
37117			return;
37118		}
37119
37120		$elements.each($.proxy(function(index, element) {
37121			var $element = $(element), image,
37122				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
37123
37124			this._core.trigger('load', { element: $element, url: url }, 'lazy');
37125
37126			if ($element.is('img')) {
37127				$element.one('load.owl.lazy', $.proxy(function() {
37128					$element.css('opacity', 1);
37129					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
37130				}, this)).attr('src', url);
37131			} else {
37132				image = new Image();
37133				image.onload = $.proxy(function() {
37134					$element.css({
37135						'background-image': 'url(' + url + ')',
37136						'opacity': '1'
37137					});
37138					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
37139				}, this);
37140				image.src = url;
37141			}
37142		}, this));
37143
37144		this._loaded.push($item.get(0));
37145	}
37146
37147	/**
37148	 * Destroys the plugin.
37149	 * @public
37150	 */
37151	Lazy.prototype.destroy = function() {
37152		var handler, property;
37153
37154		for (handler in this.handlers) {
37155			this._core.$element.off(handler, this.handlers[handler]);
37156		}
37157		for (property in Object.getOwnPropertyNames(this)) {
37158			typeof this[property] != 'function' && (this[property] = null);
37159		}
37160	};
37161
37162	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
37163
37164})(window.Zepto || window.jQuery, window, document);
37165
37166/**
37167 * AutoHeight Plugin
37168 * @version 2.0.0-beta.3
37169 * @author Bartosz Wojciechowski
37170 * @license The MIT License (MIT)
37171 */
37172;(function($, window, document, undefined) {
37173
37174	/**
37175	 * Creates the auto height plugin.
37176	 * @class The Auto Height Plugin
37177	 * @param {Owl} carousel - The Owl Carousel
37178	 */
37179	var AutoHeight = function(carousel) {
37180		/**
37181		 * Reference to the core.
37182		 * @protected
37183		 * @type {Owl}
37184		 */
37185		this._core = carousel;
37186
37187		/**
37188		 * All event handlers.
37189		 * @protected
37190		 * @type {Object}
37191		 */
37192		this._handlers = {
37193			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
37194				if (e.namespace && this._core.settings.autoHeight) {
37195					this.update();
37196				}
37197			}, this),
37198			'changed.owl.carousel': $.proxy(function(e) {
37199				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
37200					this.update();
37201				}
37202			}, this),
37203			'loaded.owl.lazy': $.proxy(function(e) {
37204				if (e.namespace && this._core.settings.autoHeight
37205					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
37206					this.update();
37207				}
37208			}, this)
37209		};
37210
37211		// set default options
37212		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
37213
37214		// register event handlers
37215		this._core.$element.on(this._handlers);
37216	};
37217
37218	/**
37219	 * Default options.
37220	 * @public
37221	 */
37222	AutoHeight.Defaults = {
37223		autoHeight: false,
37224		autoHeightClass: 'owl-height'
37225	};
37226
37227	/**
37228	 * Updates the view.
37229	 */
37230	AutoHeight.prototype.update = function() {
37231		var start = this._core._current,
37232			end = start + this._core.settings.items,
37233			visible = this._core.$stage.children().toArray().slice(start, end);
37234			heights = [],
37235			maxheight = 0;
37236
37237		$.each(visible, function(index, item) {
37238			heights.push($(item).height());
37239		});
37240
37241		maxheight = Math.max.apply(null, heights);
37242
37243		this._core.$stage.parent()
37244			.height(maxheight)
37245			.addClass(this._core.settings.autoHeightClass);
37246	};
37247
37248	AutoHeight.prototype.destroy = function() {
37249		var handler, property;
37250
37251		for (handler in this._handlers) {
37252			this._core.$element.off(handler, this._handlers[handler]);
37253		}
37254		for (property in Object.getOwnPropertyNames(this)) {
37255			typeof this[property] != 'function' && (this[property] = null);
37256		}
37257	};
37258
37259	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
37260
37261})(window.Zepto || window.jQuery, window, document);
37262
37263/**
37264 * Video Plugin
37265 * @version 2.0.0-beta.3
37266 * @author Bartosz Wojciechowski
37267 * @license The MIT License (MIT)
37268 */
37269;(function($, window, document, undefined) {
37270
37271	/**
37272	 * Creates the video plugin.
37273	 * @class The Video Plugin
37274	 * @param {Owl} carousel - The Owl Carousel
37275	 */
37276	var Video = function(carousel) {
37277		/**
37278		 * Reference to the core.
37279		 * @protected
37280		 * @type {Owl}
37281		 */
37282		this._core = carousel;
37283
37284		/**
37285		 * Cache all video URLs.
37286		 * @protected
37287		 * @type {Object}
37288		 */
37289		this._videos = {};
37290
37291		/**
37292		 * Current playing item.
37293		 * @protected
37294		 * @type {jQuery}
37295		 */
37296		this._playing = null;
37297
37298		/**
37299		 * All event handlers.
37300		 * @todo The cloned content removale is too late
37301		 * @protected
37302		 * @type {Object}
37303		 */
37304		this._handlers = {
37305			'initialized.owl.carousel': $.proxy(function(e) {
37306				if (e.namespace) {
37307					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
37308				}
37309			}, this),
37310			'resize.owl.carousel': $.proxy(function(e) {
37311				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
37312					e.preventDefault();
37313				}
37314			}, this),
37315			'refreshed.owl.carousel': $.proxy(function(e) {
37316				if (e.namespace && this._core.is('resizing')) {
37317					this._core.$stage.find('.cloned .owl-video-frame').remove();
37318				}
37319			}, this),
37320			'changed.owl.carousel': $.proxy(function(e) {
37321				if (e.namespace && e.property.name === 'position' && this._playing) {
37322					this.stop();
37323				}
37324			}, this),
37325			'prepared.owl.carousel': $.proxy(function(e) {
37326				if (!e.namespace) {
37327					return;
37328				}
37329
37330				var $element = $(e.content).find('.owl-video');
37331
37332				if ($element.length) {
37333					$element.css('display', 'none');
37334					this.fetch($element, $(e.content));
37335				}
37336			}, this)
37337		};
37338
37339		// set default options
37340		this._core.options = $.extend({}, Video.Defaults, this._core.options);
37341
37342		// register event handlers
37343		this._core.$element.on(this._handlers);
37344
37345		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
37346			this.play(e);
37347		}, this));
37348	};
37349
37350	/**
37351	 * Default options.
37352	 * @public
37353	 */
37354	Video.Defaults = {
37355		video: false,
37356		videoHeight: false,
37357		videoWidth: false
37358	};
37359
37360	/**
37361	 * Gets the video ID and the type (YouTube/Vimeo only).
37362	 * @protected
37363	 * @param {jQuery} target - The target containing the video data.
37364	 * @param {jQuery} item - The item containing the video.
37365	 */
37366	Video.prototype.fetch = function(target, item) {
37367		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
37368			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
37369			width = target.attr('data-width') || this._core.settings.videoWidth,
37370			height = target.attr('data-height') || this._core.settings.videoHeight,
37371			url = target.attr('href');
37372
37373		if (url) {
37374			id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
37375
37376			if (id[3].indexOf('youtu') > -1) {
37377				type = 'youtube';
37378			} else if (id[3].indexOf('vimeo') > -1) {
37379				type = 'vimeo';
37380			} else {
37381				throw new Error('Video URL not supported.');
37382			}
37383			id = id[6];
37384		} else {
37385			throw new Error('Missing video URL.');
37386		}
37387
37388		this._videos[url] = {
37389			type: type,
37390			id: id,
37391			width: width,
37392			height: height
37393		};
37394
37395		item.attr('data-video', url);
37396
37397		this.thumbnail(target, this._videos[url]);
37398	};
37399
37400	/**
37401	 * Creates video thumbnail.
37402	 * @protected
37403	 * @param {jQuery} target - The target containing the video data.
37404	 * @param {Object} info - The video info object.
37405	 * @see `fetch`
37406	 */
37407	Video.prototype.thumbnail = function(target, video) {
37408		var tnLink,
37409			icon,
37410			path,
37411			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
37412			customTn = target.find('img'),
37413			srcType = 'src',
37414			lazyClass = '',
37415			settings = this._core.settings,
37416			create = function(path) {
37417				icon = '<div class="owl-video-play-icon"></div>';
37418
37419				if (settings.lazyLoad) {
37420					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
37421				} else {
37422					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
37423				}
37424				target.after(tnLink);
37425				target.after(icon);
37426			};
37427
37428		// wrap video content into owl-video-wrapper div
37429		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
37430
37431		if (this._core.settings.lazyLoad) {
37432			srcType = 'data-src';
37433			lazyClass = 'owl-lazy';
37434		}
37435
37436		// custom thumbnail
37437		if (customTn.length) {
37438			create(customTn.attr(srcType));
37439			customTn.remove();
37440			return false;
37441		}
37442
37443		if (video.type === 'youtube') {
37444			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
37445			create(path);
37446		} else if (video.type === 'vimeo') {
37447			$.ajax({
37448				type: 'GET',
37449				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
37450				jsonp: 'callback',
37451				dataType: 'jsonp',
37452				success: function(data) {
37453					path = data[0].thumbnail_large;
37454					create(path);
37455				}
37456			});
37457		}
37458	};
37459
37460	/**
37461	 * Stops the current video.
37462	 * @public
37463	 */
37464	Video.prototype.stop = function() {
37465		this._core.trigger('stop', null, 'video');
37466		this._playing.find('.owl-video-frame').remove();
37467		this._playing.removeClass('owl-video-playing');
37468		this._playing = null;
37469		this._core.leave('playing');
37470		this._core.trigger('stopped', null, 'video');
37471	};
37472
37473	/**
37474	 * Starts the current video.
37475	 * @public
37476	 * @param {Event} event - The event arguments.
37477	 */
37478	Video.prototype.play = function(event) {
37479		var target = $(event.target),
37480			item = target.closest('.' + this._core.settings.itemClass),
37481			video = this._videos[item.attr('data-video')],
37482			width = video.width || '100%',
37483			height = video.height || this._core.$stage.height(),
37484			html;
37485
37486		if (this._playing) {
37487			return;
37488		}
37489
37490		this._core.enter('playing');
37491		this._core.trigger('play', null, 'video');
37492
37493		item = this._core.items(this._core.relative(item.index()));
37494
37495		this._core.reset(item.index());
37496
37497		if (video.type === 'youtube') {
37498			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
37499				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
37500		} else if (video.type === 'vimeo') {
37501			html = '<iframe src="//player.vimeo.com/video/' + video.id +
37502				'?autoplay=1" width="' + width + '" height="' + height +
37503				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
37504		}
37505
37506		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
37507
37508		this._playing = item.addClass('owl-video-playing');
37509	};
37510
37511	/**
37512	 * Checks whether an video is currently in full screen mode or not.
37513	 * @todo Bad style because looks like a readonly method but changes members.
37514	 * @protected
37515	 * @returns {Boolean}
37516	 */
37517	Video.prototype.isInFullScreen = function() {
37518		var element = document.fullscreenElement || document.mozFullScreenElement ||
37519				document.webkitFullscreenElement;
37520
37521		return element && $(element).parent().hasClass('owl-video-frame');
37522	};
37523
37524	/**
37525	 * Destroys the plugin.
37526	 */
37527	Video.prototype.destroy = function() {
37528		var handler, property;
37529
37530		this._core.$element.off('click.owl.video');
37531
37532		for (handler in this._handlers) {
37533			this._core.$element.off(handler, this._handlers[handler]);
37534		}
37535		for (property in Object.getOwnPropertyNames(this)) {
37536			typeof this[property] != 'function' && (this[property] = null);
37537		}
37538	};
37539
37540	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
37541
37542})(window.Zepto || window.jQuery, window, document);
37543
37544/**
37545 * Animate Plugin
37546 * @version 2.0.0-beta.3
37547 * @author Bartosz Wojciechowski
37548 * @license The MIT License (MIT)
37549 */
37550;(function($, window, document, undefined) {
37551
37552	/**
37553	 * Creates the animate plugin.
37554	 * @class The Navigation Plugin
37555	 * @param {Owl} scope - The Owl Carousel
37556	 */
37557	var Animate = function(scope) {
37558		this.core = scope;
37559		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
37560		this.swapping = true;
37561		this.previous = undefined;
37562		this.next = undefined;
37563
37564		this.handlers = {
37565			'change.owl.carousel': $.proxy(function(e) {
37566				if (e.namespace && e.property.name == 'position') {
37567					this.previous = this.core.current();
37568					this.next = e.property.value;
37569				}
37570			}, this),
37571			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
37572				if (e.namespace) {
37573					this.swapping = e.type == 'translated';
37574				}
37575			}, this),
37576			'translate.owl.carousel': $.proxy(function(e) {
37577				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
37578					this.swap();
37579				}
37580			}, this)
37581		};
37582
37583		this.core.$element.on(this.handlers);
37584	};
37585
37586	/**
37587	 * Default options.
37588	 * @public
37589	 */
37590	Animate.Defaults = {
37591		animateOut: false,
37592		animateIn: false
37593	};
37594
37595	/**
37596	 * Toggles the animation classes whenever an translations starts.
37597	 * @protected
37598	 * @returns {Boolean|undefined}
37599	 */
37600	Animate.prototype.swap = function() {
37601
37602		if (this.core.settings.items !== 1) {
37603			return;
37604		}
37605
37606		if (!$.support.animation || !$.support.transition) {
37607			return;
37608		}
37609
37610		this.core.speed(0);
37611
37612		var left,
37613			clear = $.proxy(this.clear, this),
37614			previous = this.core.$stage.children().eq(this.previous),
37615			next = this.core.$stage.children().eq(this.next),
37616			incoming = this.core.settings.animateIn,
37617			outgoing = this.core.settings.animateOut;
37618
37619		if (this.core.current() === this.previous) {
37620			return;
37621		}
37622
37623		if (outgoing) {
37624			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
37625			previous.css( { 'left': left + 'px' } )
37626				.addClass('animated owl-animated-out')
37627				.addClass(outgoing)
37628				.on($.support.animation.end, clear);
37629		}
37630
37631		if (incoming) {
37632			next.addClass('animated owl-animated-in')
37633				.addClass(incoming)
37634				.on($.support.animation.end, clear);
37635		}
37636	};
37637
37638	Animate.prototype.clear = function(e) {
37639		if ($(e.target).hasClass('animated')) {
37640			$(e.target).css( { 'left': '' } )
37641				.removeClass('animated owl-animated-out owl-animated-in')
37642				.removeClass(this.core.settings.animateIn)
37643				.removeClass(this.core.settings.animateOut);
37644			this.core.onTransitionEnd();
37645		}
37646	};
37647
37648	/**
37649	 * Destroys the plugin.
37650	 * @public
37651	 */
37652	Animate.prototype.destroy = function() {
37653		var handler, property;
37654
37655		for (handler in this.handlers) {
37656			this.core.$element.off(handler, this.handlers[handler]);
37657		}
37658		for (property in Object.getOwnPropertyNames(this)) {
37659			typeof this[property] != 'function' && (this[property] = null);
37660		}
37661	};
37662
37663	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
37664
37665})(window.Zepto || window.jQuery, window, document);
37666
37667/**
37668 * Autoplay Plugin
37669 * @version 2.0.0-beta.3
37670 * @author Bartosz Wojciechowski
37671 * @author Artus Kolanowski
37672 * @license The MIT License (MIT)
37673 */
37674;(function($, window, document, undefined) {
37675
37676	/**
37677	 * Creates the autoplay plugin.
37678	 * @class The Autoplay Plugin
37679	 * @param {Owl} scope - The Owl Carousel
37680	 */
37681	var Autoplay = function(carousel) {
37682		/**
37683		 * Reference to the core.
37684		 * @protected
37685		 * @type {Owl}
37686		 */
37687		this._core = carousel;
37688
37689		/**
37690		 * The autoplay interval.
37691		 * @type {Number}
37692		 */
37693		this._interval = null;
37694
37695		/**
37696		 * Indicates whenever the autoplay is paused.
37697		 * @type {Boolean}
37698		 */
37699		this._paused = false;
37700
37701		/**
37702		 * All event handlers.
37703		 * @protected
37704		 * @type {Object}
37705		 */
37706		this._handlers = {
37707			'changed.owl.carousel': $.proxy(function(e) {
37708				if (e.namespace && e.property.name === 'settings') {
37709					if (this._core.settings.autoplay) {
37710						this.play();
37711					} else {
37712						this.stop();
37713					}
37714				}
37715			}, this),
37716			'initialized.owl.carousel': $.proxy(function(e) {
37717				if (e.namespace && this._core.settings.autoplay) {
37718					this.play();
37719				}
37720			}, this),
37721			'play.owl.autoplay': $.proxy(function(e, t, s) {
37722				if (e.namespace) {
37723					this.play(t, s);
37724				}
37725			}, this),
37726			'stop.owl.autoplay': $.proxy(function(e) {
37727				if (e.namespace) {
37728					this.stop();
37729				}
37730			}, this),
37731			'mouseover.owl.autoplay': $.proxy(function() {
37732				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
37733					this.pause();
37734				}
37735			}, this),
37736			'mouseleave.owl.autoplay': $.proxy(function() {
37737				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
37738					this.play();
37739				}
37740			}, this)
37741		};
37742
37743		// register event handlers
37744		this._core.$element.on(this._handlers);
37745
37746		// set default options
37747		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
37748	};
37749
37750	/**
37751	 * Default options.
37752	 * @public
37753	 */
37754	Autoplay.Defaults = {
37755		autoplay: false,
37756		autoplayTimeout: 5000,
37757		autoplayHoverPause: false,
37758		autoplaySpeed: false
37759	};
37760
37761	/**
37762	 * Starts the autoplay.
37763	 * @public
37764	 * @param {Number} [timeout] - The interval before the next animation starts.
37765	 * @param {Number} [speed] - The animation speed for the animations.
37766	 */
37767	Autoplay.prototype.play = function(timeout, speed) {
37768		this._paused = false;
37769
37770		if (this._core.is('rotating')) {
37771			return;
37772		}
37773
37774		this._core.enter('rotating');
37775
37776		this._interval = window.setInterval($.proxy(function() {
37777			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
37778				return;
37779			}
37780			this._core.next(speed || this._core.settings.autoplaySpeed);
37781		}, this), timeout || this._core.settings.autoplayTimeout);
37782	};
37783
37784	/**
37785	 * Stops the autoplay.
37786	 * @public
37787	 */
37788	Autoplay.prototype.stop = function() {
37789		if (!this._core.is('rotating')) {
37790			return;
37791		}
37792
37793		window.clearInterval(this._interval);
37794		this._core.leave('rotating');
37795	};
37796
37797	/**
37798	 * Stops the autoplay.
37799	 * @public
37800	 */
37801	Autoplay.prototype.pause = function() {
37802		if (!this._core.is('rotating')) {
37803			return;
37804		}
37805
37806		this._paused = true;
37807	};
37808
37809	/**
37810	 * Destroys the plugin.
37811	 */
37812	Autoplay.prototype.destroy = function() {
37813		var handler, property;
37814
37815		this.stop();
37816
37817		for (handler in this._handlers) {
37818			this._core.$element.off(handler, this._handlers[handler]);
37819		}
37820		for (property in Object.getOwnPropertyNames(this)) {
37821			typeof this[property] != 'function' && (this[property] = null);
37822		}
37823	};
37824
37825	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
37826
37827})(window.Zepto || window.jQuery, window, document);
37828
37829/**
37830 * Navigation Plugin
37831 * @version 2.0.0-beta.3
37832 * @author Artus Kolanowski
37833 * @license The MIT License (MIT)
37834 */
37835;(function($, window, document, undefined) {
37836	'use strict';
37837
37838	/**
37839	 * Creates the navigation plugin.
37840	 * @class The Navigation Plugin
37841	 * @param {Owl} carousel - The Owl Carousel.
37842	 */
37843	var Navigation = function(carousel) {
37844		/**
37845		 * Reference to the core.
37846		 * @protected
37847		 * @type {Owl}
37848		 */
37849		this._core = carousel;
37850
37851		/**
37852		 * Indicates whether the plugin is initialized or not.
37853		 * @protected
37854		 * @type {Boolean}
37855		 */
37856		this._initialized = false;
vendor: 14,134 bytes, lines 37857-38385
37857
37858		/**
37859		 * The current paging indexes.
37860		 * @protected
37861		 * @type {Array}
37862		 */
37863		this._pages = [];
37864
37865		/**
37866		 * All DOM elements of the user interface.
37867		 * @protected
37868		 * @type {Object}
37869		 */
37870		this._controls = {};
37871
37872		/**
37873		 * Markup for an indicator.
37874		 * @protected
37875		 * @type {Array.<String>}
37876		 */
37877		this._templates = [];
37878
37879		/**
37880		 * The carousel element.
37881		 * @type {jQuery}
37882		 */
37883		this.$element = this._core.$element;
37884
37885		/**
37886		 * Overridden methods of the carousel.
37887		 * @protected
37888		 * @type {Object}
37889		 */
37890		this._overrides = {
37891			next: this._core.next,
37892			prev: this._core.prev,
37893			to: this._core.to
37894		};
37895
37896		/**
37897		 * All event handlers.
37898		 * @protected
37899		 * @type {Object}
37900		 */
37901		this._handlers = {
37902			'prepared.owl.carousel': $.proxy(function(e) {
37903				if (e.namespace && this._core.settings.dotsData) {
37904					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
37905						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
37906				}
37907			}, this),
37908			'added.owl.carousel': $.proxy(function(e) {
37909				if (e.namespace && this._core.settings.dotsData) {
37910					this._templates.splice(e.position, 0, this._templates.pop());
37911				}
37912			}, this),
37913			'remove.owl.carousel': $.proxy(function(e) {
37914				if (e.namespace && this._core.settings.dotsData) {
37915					this._templates.splice(e.position, 1);
37916				}
37917			}, this),
37918			'changed.owl.carousel': $.proxy(function(e) {
37919				if (e.namespace && e.property.name == 'position') {
37920					this.draw();
37921				}
37922			}, this),
37923			'initialized.owl.carousel': $.proxy(function(e) {
37924				if (e.namespace && !this._initialized) {
37925					this._core.trigger('initialize', null, 'navigation');
37926					this.initialize();
37927					this.update();
37928					this.draw();
37929					this._initialized = true;
37930					this._core.trigger('initialized', null, 'navigation');
37931				}
37932			}, this),
37933			'refreshed.owl.carousel': $.proxy(function(e) {
37934				if (e.namespace && this._initialized) {
37935					this._core.trigger('refresh', null, 'navigation');
37936					this.update();
37937					this.draw();
37938					this._core.trigger('refreshed', null, 'navigation');
37939				}
37940			}, this)
37941		};
37942
37943		// set default options
37944		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
37945
37946		// register event handlers
37947		this.$element.on(this._handlers);
37948	};
37949
37950	/**
37951	 * Default options.
37952	 * @public
37953	 * @todo Rename `slideBy` to `navBy`
37954	 */
37955	Navigation.Defaults = {
37956		nav: false,
37957		navText: [ 'prev', 'next' ],
37958		navSpeed: false,
37959		navElement: 'button type="button"',
37960		navContainer: false,
37961		navContainerClass: 'owl-nav',
37962		navClass: [ 'owl-prev', 'owl-next' ],
37963		slideBy: 1,
37964		dotClass: 'owl-dot',
37965		dotsClass: 'owl-dots',
37966		dots: true,
37967		dotsEach: false,
37968		dotsData: false,
37969		dotsSpeed: false,
37970		dotsContainer: false
37971	};
37972
37973	/**
37974	 * Initializes the layout of the plugin and extends the carousel.
37975	 * @protected
37976	 */
37977	Navigation.prototype.initialize = function() {
37978		var override,
37979			settings = this._core.settings;
37980
37981		// create DOM structure for relative navigation
37982		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
37983			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
37984
37985		this._controls.$previous = $('<' + settings.navElement[0] + '>')
37986			.addClass(settings.navClass[0])
37987			.html(settings.navText[0])
37988			.prependTo(this._controls.$relative)
37989			.on('click', $.proxy(function(e) {
37990				this.prev(settings.navSpeed);
37991			}, this));
37992		this._controls.$next = $('<' + settings.navElement[1] + '>')
37993			.addClass(settings.navClass[1])
37994			.html(settings.navText[1])
37995			.appendTo(this._controls.$relative)
37996			.on('click', $.proxy(function(e) {
37997				this.next(settings.navSpeed);
37998			}, this));
37999
38000		// create DOM structure for absolute navigation
38001		if (!settings.dotsData) {
38002			this._templates = [ $('<button>')
38003				.addClass(settings.dotClass)
38004				.append($('<span>'))
38005				.prop('outerHTML') ];
38006		}
38007
38008		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
38009			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
38010
38011		this._controls.$absolute.on('click', 'div, button', $.proxy(function(e) {
38012			var index = $(e.target).parent().is(this._controls.$absolute)
38013				? $(e.target).index() : $(e.target).parent().index();
38014
38015			e.preventDefault();
38016
38017			this.to(index, settings.dotsSpeed);
38018		}, this));
38019
38020		// override public methods of the carousel
38021		for (override in this._overrides) {
38022			this._core[override] = $.proxy(this[override], this);
38023		}
38024	};
38025
38026	/**
38027	 * Destroys the plugin.
38028	 * @protected
38029	 */
38030	Navigation.prototype.destroy = function() {
38031		var handler, control, property, override;
38032
38033		for (handler in this._handlers) {
38034			this.$element.off(handler, this._handlers[handler]);
38035		}
38036		for (control in this._controls) {
38037			this._controls[control].remove();
38038		}
38039		for (override in this.overides) {
38040			this._core[override] = this._overrides[override];
38041		}
38042		for (property in Object.getOwnPropertyNames(this)) {
38043			typeof this[property] != 'function' && (this[property] = null);
38044		}
38045	};
38046
38047	/**
38048	 * Updates the internal state.
38049	 * @protected
38050	 */
38051	Navigation.prototype.update = function() {
38052		var i, j, k,
38053			lower = this._core.clones().length / 2,
38054			upper = lower + this._core.items().length,
38055			maximum = this._core.maximum(true),
38056			settings = this._core.settings,
38057			size = settings.center || settings.autoWidth || settings.dotsData
38058				? 1 : settings.dotsEach || settings.items;
38059
38060		if (settings.slideBy !== 'page') {
38061			settings.slideBy = Math.min(settings.slideBy, settings.items);
38062		}
38063
38064		if (settings.dots || settings.slideBy == 'page') {
38065			this._pages = [];
38066
38067			for (i = lower, j = 0, k = 0; i < upper; i++) {
38068				if (j >= size || j === 0) {
38069					this._pages.push({
38070						start: Math.min(maximum, i - lower),
38071						end: i - lower + size - 1
38072					});
38073					if (Math.min(maximum, i - lower) === maximum) {
38074						break;
38075					}
38076					j = 0, ++k;
38077				}
38078				j += this._core.mergers(this._core.relative(i));
38079			}
38080		}
38081	};
38082
38083	/**
38084	 * Draws the user interface.
38085	 * @todo The option `dotsData` wont work.
38086	 * @protected
38087	 */
38088	Navigation.prototype.draw = function() {
38089		var difference,
38090			settings = this._core.settings,
38091			disabled = this._core.items().length <= settings.items,
38092			index = this._core.relative(this._core.current()),
38093			loop = settings.loop || settings.rewind;
38094
38095		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
38096
38097		if (settings.nav) {
38098			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
38099			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
38100		}
38101
38102		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
38103
38104		if (settings.dots) {
38105			difference = this._pages.length - this._controls.$absolute.children().length;
38106
38107			if (settings.dotsData && difference !== 0) {
38108				this._controls.$absolute.html(this._templates.join(''));
38109			} else if (difference > 0) {
38110				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
38111			} else if (difference < 0) {
38112				this._controls.$absolute.children().slice(difference).remove();
38113			}
38114
38115			this._controls.$absolute.find('.active').removeClass('active');
38116			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
38117		}
38118	};
38119
38120	/**
38121	 * Extends event data.
38122	 * @protected
38123	 * @param {Event} event - The event object which gets thrown.
38124	 */
38125	Navigation.prototype.onTrigger = function(event) {
38126		var settings = this._core.settings;
38127
38128		event.page = {
38129			index: $.inArray(this.current(), this._pages),
38130			count: this._pages.length,
38131			size: settings && (settings.center || settings.autoWidth || settings.dotsData
38132				? 1 : settings.dotsEach || settings.items)
38133		};
38134	};
38135
38136	/**
38137	 * Gets the current page position of the carousel.
38138	 * @protected
38139	 * @returns {Number}
38140	 */
38141	Navigation.prototype.current = function() {
38142		var current = this._core.relative(this._core.current());
38143		return $.grep(this._pages, $.proxy(function(page, index) {
38144			return page.start <= current && page.end >= current;
38145		}, this)).pop();
38146	};
38147
38148	/**
38149	 * Gets the current succesor/predecessor position.
38150	 * @protected
38151	 * @returns {Number}
38152	 */
38153	Navigation.prototype.getPosition = function(successor) {
38154		var position, length,
38155			settings = this._core.settings;
38156
38157		if (settings.slideBy == 'page') {
38158			position = $.inArray(this.current(), this._pages);
38159			length = this._pages.length;
38160			successor ? ++position : --position;
38161			position = this._pages[((position % length) + length) % length].start;
38162		} else {
38163			position = this._core.relative(this._core.current());
38164			length = this._core.items().length;
38165			successor ? position += settings.slideBy : position -= settings.slideBy;
38166		}
38167
38168		return position;
38169	};
38170
38171	/**
38172	 * Slides to the next item or page.
38173	 * @public
38174	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
38175	 */
38176	Navigation.prototype.next = function(speed) {
38177		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
38178	};
38179
38180	/**
38181	 * Slides to the previous item or page.
38182	 * @public
38183	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
38184	 */
38185	Navigation.prototype.prev = function(speed) {
38186		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
38187	};
38188
38189	/**
38190	 * Slides to the specified item or page.
38191	 * @public
38192	 * @param {Number} position - The position of the item or page.
38193	 * @param {Number} [speed] - The time in milliseconds for the transition.
38194	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
38195	 */
38196	Navigation.prototype.to = function(position, speed, standard) {
38197		var length;
38198
38199		if (!standard) {
38200			length = this._pages.length;
38201			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
38202		} else {
38203			$.proxy(this._overrides.to, this._core)(position, speed);
38204		}
38205	};
38206
38207	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
38208
38209})(window.Zepto || window.jQuery, window, document);
38210
38211/**
38212 * Hash Plugin
38213 * @version 2.0.0-beta.3
38214 * @author Artus Kolanowski
38215 * @license The MIT License (MIT)
38216 */
38217;(function($, window, document, undefined) {
38218	'use strict';
38219
38220	/**
38221	 * Creates the hash plugin.
38222	 * @class The Hash Plugin
38223	 * @param {Owl} carousel - The Owl Carousel
38224	 */
38225	var Hash = function(carousel) {
38226		/**
38227		 * Reference to the core.
38228		 * @protected
38229		 * @type {Owl}
38230		 */
38231		this._core = carousel;
38232
38233		/**
38234		 * Hash index for the items.
38235		 * @protected
38236		 * @type {Object}
38237		 */
38238		this._hashes = {};
38239
38240		/**
38241		 * The carousel element.
38242		 * @type {jQuery}
38243		 */
38244		this.$element = this._core.$element;
38245
38246		/**
38247		 * All event handlers.
38248		 * @protected
38249		 * @type {Object}
38250		 */
38251		this._handlers = {
38252			'initialized.owl.carousel': $.proxy(function(e) {
38253				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
38254					$(window).trigger('hashchange.owl.navigation');
38255				}
38256			}, this),
38257			'prepared.owl.carousel': $.proxy(function(e) {
38258				if (e.namespace) {
38259					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
38260
38261					if (!hash) {
38262						return;
38263					}
38264
38265					this._hashes[hash] = e.content;
38266				}
38267			}, this),
38268			'changed.owl.carousel': $.proxy(function(e) {
38269				if (e.namespace && e.property.name === 'position') {
38270					var current = this._core.items(this._core.relative(this._core.current())),
38271						hash = $.map(this._hashes, function(item, hash) {
38272							return item === current ? hash : null;
38273						}).join();
38274
38275					if (!hash || window.location.hash.slice(1) === hash) {
38276						return;
38277					}
38278
38279					window.location.hash = hash;
38280				}
38281			}, this)
38282		};
38283
38284		// set default options
38285		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
38286
38287		// register the event handlers
38288		this.$element.on(this._handlers);
38289
38290		// register event listener for hash navigation
38291		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
38292			var hash = window.location.hash.substring(1),
38293				items = this._core.$stage.children(),
38294				position = this._hashes[hash] && items.index(this._hashes[hash]);
38295
38296			if (position === undefined || position === this._core.current()) {
38297				return;
38298			}
38299
38300			this._core.to(this._core.relative(position), false, true);
38301		}, this));*/
38302	};
38303
38304	/**
38305	 * Default options.
38306	 * @public
38307	 */
38308	Hash.Defaults = {
38309		URLhashListener: false
38310	};
38311
38312	/**
38313	 * Destroys the plugin.
38314	 * @public
38315	 */
38316	Hash.prototype.destroy = function() {
38317		var handler, property;
38318
38319		$(window).off('hashchange.owl.navigation');
38320
38321		for (handler in this._handlers) {
38322			this._core.$element.off(handler, this._handlers[handler]);
38323		}
38324		for (property in Object.getOwnPropertyNames(this)) {
38325			typeof this[property] != 'function' && (this[property] = null);
38326		}
38327	};
38328
38329	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
38330
38331})(window.Zepto || window.jQuery, window, document);
38332
38333/**
38334 * Support Plugin
38335 *
38336 * @version 2.0.0-beta.3
38337 * @author Vivid Planet Software GmbH
38338 * @author Artus Kolanowski
38339 * @license The MIT License (MIT)
38340 */
38341;(function($, window, document, undefined) {
38342
38343	var style = $('<support>').get(0).style,
38344		prefixes = 'Webkit Moz O ms'.split(' '),
38345		events = {
38346			transition: {
38347				end: {
38348					WebkitTransition: 'webkitTransitionEnd',
38349					MozTransition: 'transitionend',
38350					OTransition: 'oTransitionEnd',
38351					transition: 'transitionend'
38352				}
38353			},
38354			animation: {
38355				end: {
38356					WebkitAnimation: 'webkitAnimationEnd',
38357					MozAnimation: 'animationend',
38358					OAnimation: 'oAnimationEnd',
38359					animation: 'animationend'
38360				}
38361			}
38362		},
38363		tests = {
38364			csstransforms: function() {
38365				return !!test('transform');
38366			},
38367			csstransforms3d: function() {
38368				return !!test('perspective');
38369			},
38370			csstransitions: function() {
38371				return !!test('transition');
38372			},
38373			cssanimations: function() {
38374				return !!test('animation');
38375			}
38376		};
38377
38378	function test(property, prefixed) {
38379		var result = false,
38380			upper = property.charAt(0).toUpperCase() + property.slice(1);
38381
38382		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
38383			if (style[property] !== undefined) {
38384				result = prefixed ? property : true;
38385				return false;
38386			}
38387		});
38388
38389		return result;
38390	}
38391
38392	function prefixed(property) {
38393		return test(property, true);
38394	}
38395
38396	if (tests.csstransitions()) {
38397		/* jshint -W053 */
38398		$.support.transition = new String(prefixed('transition'))
38399		$.support.transition.end = events.transition.end[ $.support.transition ];
38400	}
38401
38402	if (tests.cssanimations()) {
38403		/* jshint -W053 */
38404		$.support.animation = new String(prefixed('animation'))
38405		$.support.animation.end = events.animation.end[ $.support.animation ];
38406	}
38407
38408	if (tests.csstransforms()) {
38409		/* jshint -W053 */
38410		$.support.transform = new String(prefixed('transform'));
38411		$.support.transform3d = tests.csstransforms3d();
38412	}
38413
38414})(window.Zepto || window.jQuery, window, document);
38415
38416(function(window, document, undefined) {
38417
38418	/**
38419	 * Find the absolute position of an element
38420	 */
38421	var absPos = function(element) {
38422		var offsetLeft, offsetTop;
38423		offsetLeft = offsetTop = 0;
38424		if (element.offsetParent) {
38425			do {
38426				offsetLeft += element.offsetLeft;
38427				offsetTop += element.offsetTop;
38428			} while (element = element.offsetParent);
38429		}
38430		return [offsetLeft, offsetTop];
38431	};
38432
38433	/**
38434	 * @constructor Progress Circle class
38435	 * @param params.canvas Canvas on which the circles will be drawn.
38436	 * @param params.minRadius Inner radius of the innermost circle, in px.
38437	 * @param params.arcWidth Width of each circle(to be more accurate, ring).
38438	 * @param params.gapWidth Space between each circle.
38439	 * @param params.centerX X coordinate of the center of circles.
38440	 * @param params.centerY Y coordinate of the center of circles.
38441	 * @param params.infoLineBaseAngle Base angle of the info line.
38442	 * @param params.infoLineAngleInterval Angles between the info lines.
38443	 */
38444	var ProgressCircle = function(params) {
38445		this.canvas = params.canvas;
38446		this.minRadius = params.minRadius || 15;
38447		this.arcWidth = params.arcWidth || 5;
38448		this.gapWidth = params.gapWidth || 3;
38449		this.centerX = params.centerX || this.canvas.width / 2;
38450		this.centerY = params.centerY || this.canvas.height / 2;
38451		this.infoLineLength = params.infoLineLength || 60;
38452		this.horizLineLength = params.horizLineLength || 10;
38453		this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
38454		this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
38455
38456		this.context = this.canvas.getContext('2d');
38457
38458		this.width = this.canvas.width;
38459		this.height = this.canvas.height;
38460
38461		this.circles = [];
38462		this.runningCount = 0;
38463	};
38464
38465	ProgressCircle.prototype = {
38466		constructor: ProgressCircle,
38467
38468		/**
38469		 * @method Adds an progress monitor entry.
38470		 * @param params.fillColor Color to fill in the circle.
38471		 * @param params.outlineColor Color to outline the circle.
38472		 * @param params.progressListener Callback function to fetch the progress.
38473		 * @param params.infoListener Callback function to fetch the info.
38474		 * @returns this
38475		 */
38476		addEntry: function(params) {
38477			this.circles.push(new Circle({
38478				canvas: this.canvas,
38479				context: this.context,
38480				centerX: this.centerX,
38481				centerY: this.centerY,
38482				innerRadius: this.minRadius + this.circles.length *
38483					(this.gapWidth + this.arcWidth),
38484				arcWidth: this.arcWidth,
38485				infoLineLength: this.infoLineLength,
38486				horizLineLength: this.horizLineLength,
38487
38488				id: this.circles.length,
38489				fillColor: params.fillColor,
38490				outlineColor: params.outlineColor,
38491				progressListener: params.progressListener,
38492				infoListener: params.infoListener,
38493				infoLineAngle: this.infoLineBaseAngle +
38494					this.circles.length * this.infoLineAngleInterval,
38495			}));
38496
38497			return this;
38498		},
38499
38500		/**
38501		 * @method Starts the monitor and updates with the given interval.
38502		 * @param interval Interval between updates, in millisecond.
38503		 * @returns this
38504		 */
38505		start: function(interval) {
38506			var self = this;
38507			this.timer = setInterval(function() {
38508				self._update();
38509			}, interval || 33);
38510
38511			return this;
38512		},
38513
38514		/**
38515		 * @method Stop the animation.
38516		 */
38517		stop: function() {
38518			clearTimeout(this.timer);
38519		},
38520
38521		/**
38522		 * @private
38523		 * @method Call update on each circle and redraw them.
38524		 * @returns this
38525		 */
38526		_update: function() {
38527			this._clear();
38528			this.circles.forEach(function(circle, idx, array) {
38529				circle.update();
38530			});
38531
38532			return this;
38533		},
38534
38535		/**
38536		 * @private
38537		 * @method Clear the canvas.
38538		 * @returns this
38539		 */
38540		_clear: function() {
38541			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
38542
38543			return this;
38544		},
38545
38546	};
38547
38548	/**
38549	 * @private
38550	 * @class Individual progress circle.
38551	 * @param params.canvas Canvas on which the circle will be drawn.
38552	 * @param params.context Context of the canvas.
38553	 * @param params.innerRadius Inner radius of the circle, in px.
38554	 * @param params.arcWidth Width of each arc(circle).
38555	 * @param params.gapWidth Distance between each arc.
38556	 * @param params.centerX X coordinate of the center of circles.
38557	 * @param params.centerY Y coordinate of the center of circles.
38558	 * @param params.fillColor Color to fill in the circle.
38559	 * @param params.outlineColor Color to outline the circle.
38560	 * @param params.progressListener Callback function to fetch the progress.
38561	 * @param params.infoListener Callback function to fetch the info.
38562	 * @param params.infoLineAngle Angle of info line.
38563	 */
38564	var Circle = function(params) {
38565		this.id = params.id;
38566		this.canvas = params.canvas;
38567		this.context = params.context;
38568		this.centerX = params.centerX;
38569		this.centerY = params.centerY;
38570		this.arcWidth = params.arcWidth;
38571		this.innerRadius = params.innerRadius || 0;
38572		this.fillColor = params.fillColor || '#fff';
38573		this.outlineColor = params.outlineColor || this.fillColor;
38574		this.progressListener = params.progressListener;
38575		this.infoLineLength = params.infoLineLength || 250;
38576		this.horizLineLength = params.horizLineLength || 50;
38577		this.infoListener = params.infoListener;
38578		this.infoLineAngle = params.infoLineAngle;
38579
38580		this.outerRadius = this.innerRadius + this.arcWidth;
38581
38582		// If the info listener is not registered, then don't calculate
38583		// the related coordinates
38584		if (!this.infoListener) return;
38585
38586		// calculate the info-line turning points
38587		var angle = this.infoLineAngle,
38588			arcDistance = (this.innerRadius + this.outerRadius) / 2,
38589
38590			sinA = Math.sin(angle),
38591			cosA = Math.cos(angle);
38592
38593		this.infoLineStartX = this.centerX + sinA * arcDistance;
38594		this.infoLineStartY = this.centerY - cosA * arcDistance;
38595
38596		this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
38597		this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
38598
38599		this.infoLineEndX = this.infoLineMidX +
38600			 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
38601		this.infoLineEndY = this.infoLineMidY;
38602
38603		var infoText = document.createElement('div'),
38604			style = infoText.style;
38605
38606		style.color = this.fillColor;
38607		style.position = 'absolute';
38608		style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
38609		// style.top will be calculated in the `drawInfo` method. Since
38610		// user may want to change the size of the font, so the top offset
38611		// must be updated in each loop.
38612		infoText.className = 'ProgressCircleInfo'; // For css styling
38613		infoText.id = 'progress_circle_info_' + this.id;
38614		document.body.appendChild(infoText);
38615		this.infoText = infoText;
38616	};
38617
38618	Circle.prototype = {
38619		constructor: Circle,
38620
38621		update: function() {
38622			this.progress = this.progressListener();
38623			this._draw();
38624
38625			if (this.infoListener) {
38626				this.info = this.infoListener();
38627				this._drawInfo();
38628			}
38629		},
38630
38631		/**
38632		 * @private
38633		 * @method Draw the circle on the canvas.
38634		 * @returns this
38635		 */
38636		_draw: function() {
38637			var ctx = this.context,
38638
38639				ANGLE_OFFSET = -Math.PI / 2,
38640
38641				startAngle = 0 + ANGLE_OFFSET,
38642				endAngle= startAngle + this.progress * Math.PI * 2,
38643
38644				x = this.centerX,
38645				y = this.centerY,
38646
38647				innerRadius = this.innerRadius - this.arcWidth - 1,
38648				outerRadius = this.outerRadius - this.arcWidth - 1;
38649
38650			if ( innerRadius < 0 )
38651				return;
38652
38653			ctx.fillStyle = this.fillColor;
38654			ctx.strokeStyle = this.outlineColor;
38655
38656			ctx.beginPath();
38657			ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
38658			ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
38659			ctx.closePath();
38660			ctx.stroke();
38661			ctx.fill();
38662
38663			return this;
38664		},
38665
38666		/**
38667		 * @private
38668		 * @method Draw the info lines and info text.
38669		 * @returns this
38670		 */
38671		_drawInfo: function() {
38672
38673			var pointList, lineHeight;
38674
38675			pointList = [
38676				[this.infoLineStartX, this.infoLineStartY],
38677				[this.infoLineMidX, this.infoLineMidY],
38678				[this.infoLineEndX, this.infoLineEndY],
38679			];
38680			this._drawSegments(pointList, false);
38681
38682			this.infoText.innerHTML = this.info;
38683
38684			lineHeight = this.infoText.offsetHeight;
38685			this.infoText.style.top = this.infoLineEndY +
38686				absPos(this.canvas)[1] - lineHeight / 2 + 'px';
38687
38688			return this;
38689		},
38690
38691		/**
38692		 * @private
38693		 * @method Helper function to draw the segments
38694		 * @param pointList An array of points in the form of [x, y].
38695		 * @param close Whether to connect the first and last point.
38696		 */
38697		_drawSegments: function(pointList, close) {
38698			var ctx = this.context;
38699
38700			ctx.beginPath();
38701			ctx.moveTo(pointList[0][0], pointList[0][1]);
38702			for (var i = 1; i < pointList.length; ++i) {
38703				ctx.lineTo(pointList[i][0], pointList[i][1]);
38704			}
38705
38706			if (close) {
38707				ctx.closePath();
38708			}
38709			ctx.stroke();
38710		},
38711	};
38712
38713	window.ProgressCircle = ProgressCircle;
38714
38715})(window, document);
38716
38717
38718
38719
38720/* =========================================================
38721 * jquery.vc_chart.js v1.0
38722 * =========================================================
38723 * Copyright 2013 Wpbakery
38724 *
38725 * Jquery chart plugin for the Visual Composer.
38726 * ========================================================= */
38727(function($){
38728	/**
38729	 * Pie chart animated.
38730	 * @param element - DOM element
38731	 * @param options - settings object.
38732	 * @constructor
38733	 */
38734	var VcChart = function(element, options) {
38735		this.el = element;
38736		this.$el = $(this.el);
38737		var $this = this;
38738		$this.options = $.extend({
38739			color: 'wpb_button',
38740			units: '',
38741			width: '',
38742			label_selector: '.vc_pie_chart_value',
38743			back_selector: '.vc_pie_chart_back',
38744			responsive: true
38745		}, options);
38746		$this.init();
38747	};
38748	VcChart.prototype = {
38749		constructor: VcChart,
38750		_progress_v: 0,
38751		animated: false,
38752		colors: {
38753			'wpb_button': 'rgba(247, 247, 247, 1)',
38754			'btn-primary': 'rgba(0, 136, 204, 1)',
38755			'btn-info': 'rgba(88, 185, 218, 1)',
38756			'btn-success': 'rgba(106, 177, 101, 1)',
38757			'btn-warning': 'rgba(255, 153, 0, 1)',
38758			'btn-danger': 'rgba(255, 103, 91, 1)',
38759			'btn-inverse': 'rgba(85, 85, 85, 1)'
38760		},
38761		init: function() {
38762			this.setupColor();
38763			this.value = this.$el.data('pie-value')/100;
38764			this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
38765			this.$wrapper = $('.vc_pie_wrapper', this.$el);
38766			this.$label = $(this.options.label_selector, this.$el);
38767			this.$back = $(this.options.back_selector, this.$el);
38768			this.$canvas = this.$el.find('canvas');
38769			this.arcWidth = this.$el.data('pie-width') * 2;
38770			this.draw();
38771			this.setWayPoint();
38772			if(this.options.responsive === true) this.setResponsive();
38773			if (UNCODE.isMobile) this._progress_v = this.value;
38774		},
38775		setupColor: function() {
38776			// if(typeof this.colors[this.options.color] !== 'undefined') {
38777			//     this.color = this.colors[this.options.color];
38778			// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
38779			//     this.color = this.options.color;
38780			// } else {
38781			//     this.color = 'rgba(247, 247, 247, 0.2)';
38782			// }
38783			if(typeof this.options.color !== 'undefined') {
38784				this.color = this.options.color;
38785			} else this.color = 'rgba(247, 247, 247, 0.2)';
38786
38787		},
38788		setResponsive: function() {
38789			var that = this;
38790			if (!UNCODE.isMobile) {
38791				$(window).resize(function(){
38792					if(that.animated === true) that.circle.stop();
38793					that.draw(true);
38794				});
38795			}
38796		},
38797		draw: function(redraw) {
38798			var w = this.$el.addClass('vc_ready').width() * 2,
38799				border_w = this.arcWidth,
38800				radius;
38801			if(!w) w = this.$el.parents(':visible').first().width()-2;
38802			//w = Math.round(w/100*80);
38803			//if (w < 250) w = 250;
38804			radius = w/2;
38805			this.$wrapper.css({"width" : (w / 2) + "px"});
38806			this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
38807			this.$back.css({"width" : (w / 2), "height" : (w / 2)});
38808			this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
38809			this.$el.addClass('vc_ready');
38810			this.circle = new ProgressCircle({
38811				canvas: this.$canvas.get(0),
38812				minRadius: radius,
38813				arcWidth: border_w
38814			});
38815			if(redraw === true && this.animated === true) {
38816				this._progress_v = this.value;
38817				this.circle.addEntry({
38818					fillColor: this.color,
38819					progressListener: $.proxy(this.setProgress, this)
38820				}).start();
38821			}
38822		},
38823		setProgress: function() {
38824			if (this._progress_v >= this.value) {
38825				this.circle.stop();
38826				this.animated = true;
38827				this.$label.html(this.label_value + this.options.units);
38828				return this._progress_v;
38829			}
38830			this._progress_v += 0.01;
38831			if (!isNaN(this.label_value)) {
38832				var label_value = this._progress_v/this.value*this.label_value;
38833				var val = Math.round(label_value) + this.options.units;
38834				this.$label.html(val);
38835			} else this.$label.html(this.label_value + this.options.units);
38836			return this._progress_v;
38837		},
38838		animate: function() {
38839			if(this.animated !== true) {
38840				this.circle.addEntry({
38841					fillColor: this.color,
38842					progressListener: $.proxy(this.setProgress, this)
38843				}).start(10);
38844			}
38845		},
38846		setWayPoint: function() {
38847			if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
38848				this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
38849			} else {
38850				this.animate();
38851			}
38852		}
38853	};
38854	/**
38855	 * jQuery plugin
38856	 * @param option - object with settings
38857	 * @return {*}
38858	 */
38859	$.fn.vcChat = function(option, value) {
38860		return this.each(function () {
38861			var $this = $(this),
38862				data = $this.data('vc_chart'),
38863				options = typeof option === 'object' ? option : {
38864					color: $this.data('pie-color'),
38865					units: $this.data('pie-units')
38866				};
38867			if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
38868			if (typeof option == 'string') data[option](value);
38869		});
38870	};
38871	/**
38872	 * Allows users to rewrite function inside theme.
38873	 */
38874	if ( typeof window['vc_pieChart'] !== 'function' ) {
38875		window.vc_pieChart = function() {
38876			$('.vc_pie_chart:visible:not(.vc_ready)').vcChat();
38877		}
38878	}
38879	$(document).ready(function(){
38880		!window.vc_iframe && vc_pieChart();
38881
38882		/**
38883		* Tab and collapse integration.
38884		*/
38885		$('.nav-tabs a').on('shown.bs.tab', function(e){
38886			var $cont = $(e.target).closest('.tab-container'),
38887				$active = $('.tab-pane.active', $cont);
38888			$('.vc_pie_chart:not(.vc_ready)', $active).vcChat();
38889		});
38890
38891		$('.panel-collapse').on('shown.bs.collapse', function (e) {
38892			$('.vc_pie_chart:not(.vc_ready)', e.target).vcChat();
38893		})
38894	});
38895
38896})(window.jQuery);
38897
38898/* Progress bar
38899 ---------------------------------------------------------- */
38900function uncode_progress_bar() {
38901	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
38902		if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) {
38903			return;
38904		}
38905		if (!UNCODE.isMobile) {
38906			new Waypoint({
38907				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
38908				element: val,
38909				handler: function() {
38910					var element = jQuery(this.element);
38911					element.find('.vc_single_bar').each(function(index) {
38912						var $this = jQuery(this),
38913							bar = $this.find('.vc_bar'),
38914							val = bar.data('percentage-value');
38915						setTimeout(function() {
38916							bar.css({
38917								"width": val + '%'
38918							});
38919						}, index * 200);
38920					});
38921				},
38922				offset: '80%'
38923			});
38924		} else {
38925			var element = jQuery(val);
38926			element.find('.vc_single_bar').each(function(index) {
38927				var $this = jQuery(this),
38928					bar = $this.find('.vc_bar'),
38929					val = bar.data('percentage-value');
38930				setTimeout(function() {
38931					bar.css({
38932						"width": val + '%'
38933					});
38934				}, index * 200);
38935			});
38936		}
38937	});
38938};
38939uncode_progress_bar();
38940
38941/*!
38942 * jquery.counterup.js 1.0
38943 *
38944 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
38945 * Released under the GPL v2 License
38946 *
38947 * Date: Nov 26, 2013
38948 */
38949(function($) {
38950	"use strict";
38951	$.fn.counterUp = function(options) {
38952		// Defaults
38953		var settings = $.extend({
38954			'time': 400,
38955			'delay': 10
38956		}, options);
38957		return this.each(function() {
38958			// Store the object
38959			var $this = $(this);
38960			var $settings = settings;
38961			var counterUpper = function() {
38962				var nums = [];
38963				var divisions = $settings.time / $settings.delay;
38964				var numReal = $this.attr('data-val'),
38965				num = numReal;
38966				var isComma = /[0-9]+,[0-9]+/.test(num);
38967				num = num.replace(/,/g, '');
38968				var isInt = /^[0-9]+$/.test(num);
38969				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
38970				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
38971				// Generate list of incremental numbers to display
38972				for (var i = divisions; i >= 1; i--) {
38973					// Preserve as int if input was int
38974					var newNum = parseInt(num / divisions * i);
38975					// Preserve float if input was float
38976					if (isFloat) {
38977						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
38978					}
38979					// Preserve commas if input had commas
38980					if (isComma) {
38981						while (/(\d+)(\d{3})/.test(newNum.toString())) {
38982							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
38983						}
38984					}
38985					nums.unshift(newNum);
38986				}
38987				nums.push(numReal);
38988				$this.data('counterup-nums', nums);
38989				$this.text('0');
38990				// Updates the number until we're done
38991				var f = function() {
38992					if ($this.data('counterup-nums') != null) {
38993						$this.text($this.data('counterup-nums').shift());
38994						if ($this.data('counterup-nums').length) {
38995							setTimeout($this.data('counterup-func'), $settings.delay);
38996						} else {
38997							delete $this.data('counterup-nums');
38998							$this.data('counterup-nums', null);
38999							$this.data('counterup-func', null);
39000						}
39001					}
39002				};
39003				$this.data('counterup-func', f);
39004				// Start the count up
39005				setTimeout($this.data('counterup-func'), $settings.delay);
39006			};
39007			// Perform counts when the element gets into view
39008			new Waypoint({
39009				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
39010				element: this,
39011				handler: function() {
39012					counterUpper();
39013					if (!UNCODE.isUnmodalOpen) {
39014						this.destroy();
39015					}
39016				},
39017				offset: '100%'
39018			});
39019		});
39020	};
39021})(jQuery);
39022
39023/*!
39024 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
39025 * Copyright (c) 2016 Edson Hilios
39026 *
39027 * Permission is hereby granted, free of charge, to any person obtaining a copy of
39028 * this software and associated documentation files (the "Software"), to deal in
39029 * the Software without restriction, including without limitation the rights to
39030 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
39031 * the Software, and to permit persons to whom the Software is furnished to do so,
39032 * subject to the following conditions:
39033 *
39034 * The above copyright notice and this permission notice shall be included in all
39035 * copies or substantial portions of the Software.
39036 *
39037 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39038 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
39039 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
39040 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39041 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39042 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39043 */
39044(function(factory) {
39045	"use strict";
39046	if (typeof define === "function" && define.amd) {
39047		define([ "jquery" ], factory);
39048	} else {
39049		factory(jQuery);
39050	}
39051})(function($) {
39052	"use strict";
39053	var instances = [], matchers = [], defaultOptions = {
39054		precision: 100,
39055		elapse: false,
39056		defer: false
39057	};
39058	matchers.push(/^[0-9]*$/.source);
39059	matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
39060	matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
39061	matchers = new RegExp(matchers.join("|"));
39062	function parseDateString(dateString) {
39063		if (dateString instanceof Date) {
39064			return dateString;
39065		}
39066		if (String(dateString).match(matchers)) {
39067			if (String(dateString).match(/^[0-9]*$/)) {
39068				dateString = Number(dateString);
39069			}
39070			if (String(dateString).match(/\-/)) {
39071				dateString = String(dateString).replace(/\-/g, "/");
39072			}
39073			return new Date(dateString);
39074		} else {
39075			throw new Error("Couldn't cast `" + dateString + "` to a date object.");
39076		}
39077	}
39078	var DIRECTIVE_KEY_MAP = {
39079		Y: "years",
39080		m: "months",
39081		n: "daysToMonth",
39082		d: "daysToWeek",
39083		w: "weeks",
39084		W: "weeksToMonth",
39085		H: "hours",
39086		M: "minutes",
39087		S: "seconds",
39088		D: "totalDays",
39089		I: "totalHours",
39090		N: "totalMinutes",
39091		T: "totalSeconds"
39092	};
39093	function escapedRegExp(str) {
39094		var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
39095		return new RegExp(sanitize);
39096	}
39097	function strftime(offsetObject) {
39098		return function(format) {
39099			var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
39100			if (directives) {
39101				for (var i = 0, len = directives.length; i < len; ++i) {
39102					var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
39103					directive = directive[2];
39104					if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
39105						value = DIRECTIVE_KEY_MAP[directive];
39106						value = Number(offsetObject[value]);
39107					}
39108					if (value !== null) {
39109						if (modifier === "!") {
39110							value = pluralize(plural, value);
39111						}
39112						if (modifier === "") {
39113							if (value < 10) {
39114								value = "0" + value.toString();
39115							}
39116						}
39117						format = format.replace(regexp, value.toString());
39118					}
39119				}
39120			}
39121			format = format.replace(/%%/, "%");
39122			return format;
39123		};
39124	}
39125	function pluralize(format, count) {
39126		var plural = "s", singular = "";
39127		if (format) {
39128			format = format.rep
vendor: 8,618 bytes, lines 39128-39272
39128lace(/(:|;|\s)/gi, "").split(/\,/);
39129			if (format.length === 1) {
39130				plural = format[0];
39131			} else {
39132				singular = format[0];
39133				plural = format[1];
39134			}
39135		}
39136		if (Math.abs(count) > 1) {
39137			return plural;
39138		} else {
39139			return singular;
39140		}
39141	}
39142	var Countdown = function(el, finalDate, options) {
39143		this.el = el;
39144		this.$el = $(el);
39145		this.interval = null;
39146		this.offset = {};
39147		this.options = $.extend({}, defaultOptions);
39148		this.instanceNumber = instances.length;
39149		instances.push(this);
39150		this.$el.data("countdown-instance", this.instanceNumber);
39151		if (options) {
39152			if (typeof options === "function") {
39153				this.$el.on("update.countdown", options);
39154				this.$el.on("stoped.countdown", options);
39155				this.$el.on("finish.countdown", options);
39156			} else {
39157				this.options = $.extend({}, defaultOptions, options);
39158			}
39159		}
39160		this.setFinalDate(finalDate);
39161		if (this.options.defer === false) {
39162			this.start();
39163		}
39164	};
39165	$.extend(Countdown.prototype, {
39166		start: function() {
39167			if (this.interval !== null) {
39168				clearInterval(this.interval);
39169			}
39170			var self = this;
39171			this.update();
39172			this.interval = setInterval(function() {
39173				self.update.call(self);
39174			}, this.options.precision);
39175		},
39176		stop: function() {
39177			clearInterval(this.interval);
39178			this.interval = null;
39179			this.dispatchEvent("stoped");
39180		},
39181		toggle: function() {
39182			if (this.interval) {
39183				this.stop();
39184			} else {
39185				this.start();
39186			}
39187		},
39188		pause: function() {
39189			this.stop();
39190		},
39191		resume: function() {
39192			this.start();
39193		},
39194		remove: function() {
39195			this.stop.call(this);
39196			instances[this.instanceNumber] = null;
39197			delete this.$el.data().countdownInstance;
39198		},
39199		setFinalDate: function(value) {
39200			this.finalDate = parseDateString(value);
39201		},
39202		update: function() {
39203			if (this.$el.closest("html").length === 0) {
39204				this.remove();
39205				return;
39206			}
39207			var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
39208			newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
39209			newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
39210			newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
39211			if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
39212				return;
39213			} else {
39214				this.totalSecsLeft = newTotalSecsLeft;
39215			}
39216			this.elapsed = now >= this.finalDate;
39217			this.offset = {
39218				seconds: this.totalSecsLeft % 60,
39219				minutes: Math.floor(this.totalSecsLeft / 60) % 60,
39220				hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
39221				days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
39222				daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
39223				daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
39224				weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
39225				weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
39226				months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
39227				years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
39228				totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
39229				totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
39230				totalMinutes: Math.floor(this.totalSecsLeft / 60),
39231				totalSeconds: this.totalSecsLeft
39232			};
39233			if (!this.options.elapse && this.totalSecsLeft === 0) {
39234				this.stop();
39235				this.dispatchEvent("finish");
39236			} else {
39237				this.dispatchEvent("update");
39238			}
39239		},
39240		dispatchEvent: function(eventName) {
39241			var event = $.Event(eventName + ".countdown");
39242			event.finalDate = this.finalDate;
39243			event.elapsed = this.elapsed;
39244			event.offset = $.extend({}, this.offset);
39245			event.strftime = strftime(this.offset);
39246			this.$el.trigger(event);
39247		}
39248	});
39249	$.fn.countdown = function() {
39250		var argumentsArray = Array.prototype.slice.call(arguments, 0);
39251		return this.each(function() {
39252			var instanceNumber = $(this).data("countdown-instance");
39253			if (instanceNumber !== undefined) {
39254				var instance = instances[instanceNumber], method = argumentsArray[0];
39255				if (Countdown.prototype.hasOwnProperty(method)) {
39256					instance[method].apply(instance, argumentsArray.slice(1));
39257				} else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
39258					instance.setFinalDate.call(instance, method);
39259					instance.start();
39260				} else {
39261					$.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
39262				}
39263			} else {
39264				new Countdown(this, argumentsArray[0], argumentsArray[1]);
39265			}
39266		});
39267	};
39268});
39269
39270!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Share=e()}}(function(){var define,module,exports;
39271function getStyles(config){
39272  // return ""+config.selector+"{width:92px;height:20px;-webkit-touch-callout:none;-khtml-user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}"+config.selector+" [class*=social-]:before{font-family:'uncodeicon'}"+config.selector+" label{font-size:16px;cursor:pointer;margin:0;padding:5px 10px;border-radius:5px;background:#a29baa;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" label:hover{opacity:.8}"+config.selector+" label span{text-transform:uppercase;font-size:.9em;font-family:Lato,sans-serif;font-weight:700;-webkit-font-smoothing:antialiased;padding-left:6px}"+config.selector+" .social{opacity:0;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;margin-left:-15px;visibility:hidden}"+config.selector+" .social.top{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:-80px}"+config.selector+" .social.bottom{-webkit-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;margin-top:5px}"+config.selector+" .social.middle{margin-top:-34px}"+config.selector+" .social.middle.right{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%;margin-left:105px}"+config.selector+" .social.middle.left{-webkit-transform-origin:5% 50%;-ms-transform-origin:5% 50%;transform-origin:5% 50%}"+config.selector+" .social.right{margin-left:14px}"+config.selector+" .social.load{-webkit-transition:none!important;transition:none!important}"+config.selector+" .social.networks-1{width:60px}"+config.selector+" .social.networks-1.center,"+config.selector+" .social.networks-1.left{margin-left:14px}"+config.selector+" .social.networks-1.middle.left{margin-left:-70px}"+config.selector+" .social.networks-1 ul{width:60px}"+config.selector+" .social.networks-2{width:120px}"+config.selector+" .social.networks-2.center{margin-left:-13px}"+config.selector+" .social.networks-2.left{margin-left:-44px}"+config.selector+" .social.networks-2.middle.left{margin-left:-130px}"+config.selector+" .social.networks-2 ul{width:120px}"+config.selector+" .social.networks-3{width:180px}"+config.selector+" .social.networks-3.center{margin-left:-45px}"+config.selector+" .social.networks-3.left{margin-left:-102px}"+config.selector+" .social.networks-3.middle.left{margin-left:-190px}"+config.selector+" .social.networks-3 ul{width:180px}"+config.selector+" .social.networks-4{width:240px}"+config.selector+" .social.networks-4.center{margin-left:-75px}"+config.selector+" .social.networks-4.left{margin-left:162px}"+config.selector+" .social.networks-4.middle.left{margin-left:-250px}"+config.selector+" .social.networks-4 ul{width:240px}"+config.selector+" .social.networks-5{width:300px}"+config.selector+" .social.networks-5.center{margin-left:-105px}"+config.selector+" .social.networks-5.left{margin-left:-225px}"+config.selector+" .social.networks-5.middle.left{margin-left:-320px}"+config.selector+" .social.networks-5 ul{width:300px}"+config.selector+" .social.active{opacity:1;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;visibility:visible}"+config.selector+" .social.active.top{-webkit-transform:scale(1) translateY(-20px);-ms-transform:scale(1) translateY(-20px);transform:scale(1) translateY(-20px)}"+config.selector+" .social.active.bottom{-webkit-transform:scale(1) translateY(15px);-ms-transform:scale(1) translateY(15px);transform:scale(1) translateY(15px)}"+config.selector+" .social.active.middle.right{-webkit-transform:scale(1) translateX(10px);-ms-transform:scale(1) translateX(10px);transform:scale(1) translateX(10px)}"+config.selector+" .social.active.middle.left{-webkit-transform:scale(1) translateX(-20px);-ms-transform:scale(1) translateX(-20px);transform:scale(1) translateX(-20px)}"+config.selector+" .social ul{position:relative;
39272left:0;right:0;height:46px;color:#fff;margin:auto;padding:0;list-style:none}"+config.selector+" .social ul li{font-size:20px;cursor:pointer;width:60px;margin:0;padding:12px 0;text-align:center;float:left;display:none;height:22px;position:relative;z-index:2;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}"+config.selector+" .social ul li:hover{}"+config.selector+" .social li[class*=facebook]{display:"+config.networks.facebook.display+"}"+config.selector+" .social li[class*=twitter]{display:"+config.networks.twitter.display+"}"+config.selector+" .social li[class*=gplus]{display:"+config.networks.google_plus.display+"}"+config.selector+" .social li[class*=pinterest]{display:"+config.networks.pinterest.display+"}"+config.selector+" .social li[class*=paper-plane]{display:"+config.networks.email.display+"}"
39273};
39274  var ShareUtils;
39275
39276if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
39277  Object.defineProperty(HTMLElement.prototype, "classList", {
39278    get: function() {
39279      var ret, self, update;
39280      update = function(fn) {
39281        return function(value) {
39282          var classes, index;
39283          classes = self.className.split(/\s+/);
39284          index = classes.indexOf(value);
39285          fn(classes, index, value);
39286          self.className = classes.join(" ");
39287        };
39288      };
39289      self = this;
39290      ret = {
39291        add: update(function(classes, index, value) {
39292          ~index || classes.push(value);
39293        }),
39294        remove: update(function(classes, index) {
39295          ~index && classes.splice(index, 1);
39296        }),
39297        toggle: update(function(classes, index, value) {
39298          if (~index) {
39299            classes.splice(index, 1);
39300          } else {
39301            classes.push(value);
39302          }
39303        }),
39304        contains: function(value) {
39305          return !!~self.className.split(/\s+/).indexOf(value);
39306        },
39307        item: function(i) {
39308          return self.className.split(/\s+/)[i] || null;
39309        }
39310      };
39311      Object.defineProperty(ret, "length", {
39312        get: function() {
39313          return self.className.split(/\s+/).length;
39314        }
39315      });
39316      return ret;
39317    }
39318  });
39319}
39320
39321String.prototype.to_rfc3986 = function() {
39322  var tmp;
39323  tmp = encodeURIComponent(this);
39324  return tmp.replace(/[!'()*]/g, function(c) {
39325    return "%" + c.charCodeAt(0).toString(16);
39326  });
39327};
39328
39329ShareUtils = (function() {
39330  function ShareUtils() {}
39331
39332  ShareUtils.prototype.extend = function(to, from, overwrite) {
39333    var hasProp, prop;
39334    for (prop in from) {
39335      hasProp = to[prop] !== undefined;
39336      if (hasProp && typeof from[prop] === "object") {
39337        this.extend(to[prop], from[prop], overwrite);
39338      } else {
39339        if (overwrite || !hasProp) {
39340          to[prop] = from[prop];
39341        }
39342      }
39343    }
39344  };
39345
39346  ShareUtils.prototype.hide = function(el) {
39347    return el.style.display = "none";
39348  };
39349
39350  ShareUtils.prototype.show = function(el) {
39351    return el.style.display = "block";
39352  };
39353
39354  ShareUtils.prototype.has_class = function(el, class_name) {
39355    return el.classList.contains(class_name);
39356  };
39357
39358  ShareUtils.prototype.add_class = function(el, class_name) {
39359    return el.classList.add(class_name);
39360  };
39361
39362  ShareUtils.prototype.remove_class = function(el, class_name) {
39363    return el.classList.remove(class_name);
39364  };
39365
39366  ShareUtils.prototype.is_encoded = function(str) {
39367    str = str.to_rfc3986();
39368    return decodeURIComponent(str) !== str;
39369  };
39370
39371  ShareUtils.prototype.encode = function(str) {
39372    if (typeof str === "undefined" || this.is_encoded(str)) {
39373      return str;
39374    } else {
39375      return str.to_rfc3986();
39376    }
39377  };
39378
39379  ShareUtils.prototype.popup = function(url, params) {
39380    var k, popup, qs, v;
39381    if (params == null) {
39382      params = {};
39383    }
39384    popup = {
39385      width: 500,
39386      height: 350
39387    };
39388    popup.top = (screen.height / 2) - (popup.height / 2);
39389    popup.left = (screen.width / 2) - (popup.width / 2);
39390    qs = ((function() {
39391      var _results;
39392      _results = [];
39393      for (k in params) {
39394        v = params[k];
39395        _results.push("" + k + "=" + (this.encode(v)));
39396      }
39397      return _results;
39398    }).call(this)).join('&');
39399    if (qs) {
39400      qs = "?" + qs;
39401    }
39402    return window.open(url + qs, 'targetWindow', "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,left=" + popup.left + ",top=" + popup.top + ",width=" 
39402+ popup.width + ",height=" + popup.height);
39403  };
39404
39405  return ShareUtils;
39406
39407})();
39408var Share,
39409  __hasProp = {}.hasOwnProperty,
39410  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
39411
39412Share = (function(_super) {
39413  __extends(Share, _super);
39414
39415  function Share(element, options) {
39416    this.element = element;
39417    this.el = {
39418      head: document.getElementsByTagName('head')[0],
39419      body: document.getElementsByTagName('body')[0]
39420    };
39421    this.config = {
39422      enabled_networks: 0,
39423      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
39424      url: window.location.href.replace("&", "%26"),
39425      caption: null,
39426      title: this.default_title(),
39427      image: this.default_image(),
39428      description: this.default_description(),
39429      ui: {
39430        flyout: 'top center',
39431        button_text: 'Share',
39432        button_font: true,
39433        icon_font: true
39434      },
39435      networks: {
39436        twitter: {
39437          enabled: true,
39438          url: null,
39439          title: null,
39440          description: null
39441        },
39442        facebook: {
39443          enabled: true,
39444          load_sdk: true,
39445          url: null,
39446          app_id: null,
39447          title: null,
39448          caption: null,
39449          description: null,
39450          image: null
39451        },
39452        threads: {
39453          enabled: true,
39454          url: null,
39455          title: null,
39456          description: null
39457        },
39458        bluesky: {
39459          enabled: true,
39460          url: null,
39461          title: null,
39462          description: null
39463        },
39464        pinterest: {
39465          enabled: true,
39466          url: null,
39467          image: null,
39468          description: null
39469        },
39470        reddit: {
39471          enabled: true,
39472          url: null,
39473          title: null
39474        },
39475        linkedin: {
39476          enabled: true,
39477          url: null,
39478          title: null,
39479          description: null
39480        },
39481        xing: {
39482          enabled: true,
39483          url: null,
39484          title: null,
39485          image: null,
39486          description: null
39487        },
39488        whatsapp: {
39489          enabled: true,
39490          title: null,
39491          url: null
39492        },
39493        email: {
39494          enabled: true,
39495          title: null,
39496          description: null,
39497          url: null
39498        }
39499      }
39500    };
39501    this.setup(element, options);
39502    return this;
39503  }
39504
39505  Share.prototype.setup = function(element, opts) {
39506    var index, instance, instances, _i, _len;
39507    instances = document.querySelectorAll(element);
39508    this.extend(this.config, opts, true);
39509    this.set_global_configuration();
39510    this.normalize_network_configuration();
39511    if (this.config.ui.icon_font) {
39512      this.inject_icons();
39513    }
39514    if (this.config.ui.button_font) {
39515      this.inject_fonts();
39516    }
39517    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
39518      this.inject_facebook_sdk();
39519    }
39520    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
39521      instance = instances[index];
39522      this.setup_instance(element, index);
39523    }
39524  };
39525
39526  Share.prototype.setup_instance = function(element, index) {
39527    var button, instance, label, network, networks, _i, _len, _results,
39528      _this = this;
39529    instance = document.querySelectorAll(element)[index];
39530    this.hide(instance);
39531    this.add_class(instance, "sharer-" + index);
39532    instance = document.querySelectorAll(element)[index];
39533    this.inject_css(instance);
39534    this.inject_html(instance);
39535    this.show(instance);
39536    label = instance.getElementsByTagName("label")[0];
39537    button = instance.getElementsByClassName("social")[0];
39538    networks = instance.getElementsByTagName('li');
39539    this.add_class(button, "networks-" + this.config.enabled_networks);
39540    label.addEventListener("click", function() {
39541      return _this.event_toggle(button);
39542    });
39543    _this = this;
39544    _results = [];
39545    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
39546      network = networks[index];
39547      _results.push(network.addEventListener("click", function() {
39548        _this.event_network(instance, this);
39549        return _this.event_close(button);
39550      }));
39551    }
39552    return _results;
39553  };
39554
39555  Share.prototype.event_toggle = function(button) {
39556    if (this.has_class(button, "active")) {
39557      return this.event_close(button);
39558    } else {
39559      return this.event_open(button);
39560    }
39561  };
39562
39563  Share.prototype.event_open = function(button) {
39564    if (this.has_class(button, "load")) {
39565      this.remove_class(button, "load");
39566    }
39567    return this.add_class(button, "active");
39568  };
39569
39570  Share.prototype.event_close = function(button) {
39571    return this.remove_class(button, "active");
39572  };
39573
39574  Share.prototype.event_network = function(instance, network) {
39575    var name;
39576    name = network.getAttribute("data-network");
39577    this.hook("before", name, instance);
39578    this["network_" + name]();
39579    return this.hook("after", name, instance);
39580  };
39581
39582  Share.prototype.open = function() {
39583    return this["public"]("open");
39584  };
39585
39586  Share.prototype.close = function() {
39587    return this["public"]("close");
39588  };
39589
39590  Share.prototype.toggle = function() {
39591    return this["public"]("toggle");
39592  };
39593
39594  Share.prototype["public"] = function(action) {
39595    var button, index, instance, _i, _len, _ref, _results;
39596    _ref = document.querySelectorAll(this.element);
39597    _results = [];
39598    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
39599      instance = _ref[index];
39600      button = instance.getElementsByClassName("social")[0];
39601      _results.push(this["event_" + action](button));
39602    }
39603    return _results;
39604  };
39605
39606  Share.prototype.network_facebook = function() {
39607    if (this.config.networks.facebook.load_sdk) {
39608      if (!window.FB) {
39609        return console.error("The Facebook JS SDK hasn't loaded yet.");
39610      }
39611      return FB.ui({
39612        method: 'feed',
39613        name: this.config.networks.facebook.title,
39614        link: this.config.networks.facebook.url,
39615        picture: this.config.networks.facebook.image,
39616        caption: this.config.networks.facebook.caption,
39617        description: this.config.networks.facebook.description
39618      });
39619    } else {
39620      return this.popup('https://www.facebook.com/sharer/sharer.php', {
39621        u: this.config.networks.facebook.url
39622      });
39623    }
39624  };
39625
39626  Share.prototype.network_threads = function() {
39627    return this.popup('https://threads.net/intent/post', {
39628      text: this.config.networks.threads.title,
39629      url: this.config.networks.threads.url
39630    });
39631  };
39632
39633  Share.prototype.network_bluesky = function() {
39634    return this.popup('https://bsky.app/intent/compose', {
39635      text: this.config.networks.bluesky.title + ' ' + this.config.networks.bluesky.url
39636    });
39637  };
39638
39639  Share.prototype.network_twitter = function() {
39640    return this.popup('https://twitter.com/intent/tweet', {
39641      text: this.config.networks.twitter.title,
39642      url: this.config.networks.twitter.url
39643    });
39644  };
39645
39646  Share.prototype.network_pinterest = function() {
39647    return this.popup('https://www.pinterest.com/pin/create/button', {
39648      url: this.config.networks.pinterest.url,
39649      media: this.config.networks.pinterest.image,
39650      description: this.config.networks.pinterest.description
39651    });
39652  };
39653
39654  Share.prototype.network_linkedin = function() {
39655    return this.popup('https://www.linkedin.com/shareArticle', {
39656      url: this.config.networks.linkedin.url,
39657      title: this.config.networks.linkedin.title,
39658      summary: this.config.networks.linkedin.description
39659    });
39660  }
39661
39662  Share.prototype.network_xing = function() {
39663    return this.popup('https://www.xing.com/spi/shares/new', {
39664      url: this.config.networks.xing.url,
39665      image: this.config.networks.xing.image,
39666      title: this.config.networks.xing.title,
39667      summary: this.config.networks.xing.description
39668    });
39669  }
39670
39671  Share.prototype.network_whatsapp = function() {
39672    return this.popup('https://api.whatsapp.com/send', {
39673      text: this.config.networks.whatsapp.title + '%20' + this.config.networks.whatsapp.url,
39674    });
39675  }
39676
39677  Share.prototype.network_email = function() {
39678    return this.popup('mailto:', {
39679      subject: this.config.networks.email.title,
39680      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
39681    });
39682  };
39683
39684  Share.prototype.inject_icons = function() {
39685  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
39686  };
39687
39688  Share.prototype.inject_fonts = function() {
39689   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
39690  };
39691
39692  Share.prototype.inject_stylesheet = function(url) {
39693    var link;
39694    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
39695      link = document.createElement("link");
39696      link.setAttribute("rel", "stylesheet");
39697      link.setAttribute("href", url);
39698      return this.el.head.appendChild(link);
39699    }
39700  };
39701
39702  Share.prototype.inject_css = function(instance) {
39703    var css, meta, selector, style;
39704    selector = "." + (instance.getAttribute('class').split(" ").join("."));
39705    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
39706      this.config.selector = selector;
39707      css = getStyles(this.config);
39708      style = document.createElement("style");
39709      style.type = "text/css";
39710      if (style.styleSheet) {
39711        style.styleSheet.cssText = css;
39712      } else {
39713        style.appendChild(document.createTextNode(css));
39714      }
39715      this.el.head.appendChild(style);
39716      delete this.config.selector;
39717      meta = document.createElement("meta");
39718      meta.setAttribute("name", "sharer" + selector);
39719      return this.el.head.appendChild(meta);
39720    }
39721  };
39722
39723  Share.prototype.inject_html = function(instance) {
39724    // return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-gplus' data-network='google_plus' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>";
39725    return instance.innerHTML = "<label class='social-export'><span>" + this.config.ui.button_text + "</span></label><div class='social load " + this.config.ui.flyout + "'><ul><li class='social-facebook' data-network='facebook' tabindex='0'></li><li class='social-twitter' data-network='twitter' tabindex='0'></li><li class='social-threads' data-network='threads' tabindex='0'></li><li class='social-pinterest' data-network='pinterest' tabindex='0'></li><li class='social-linkedin' data-network='linkedin' tabindex='0'></li><li class='social-whatsapp' data-network='whatsapp' tabindex='0'></li><li class='social-bluesky' data-network='bluesky' tabindex='0'></li><li class='social-xing' data-network='xing' tabindex='0'></li><li class='social-paper-plane' data-network='email' tabindex='0'></li></ul></div>";
39726  };
39727
39728  Share.prototype.inject_facebook_sdk = function() {
39729    var fb_root, script;
39730    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
39731      script = document.createElement("script");
39732      script.text = "window.fbAsyncInit=function(){FB.init({appId:'" + this.config.networks.facebook.app_id + "',status:true,xfbml:true})};(function(e,t,n){var r,i=e.getElementsByTagName(t)[0];if(e.getElementById(n)){return}r=e.createElement(t);r.id=n;r.src='" + this.config.protocol + "connect.facebook.net/en_US/all.js';i.parentNode.insertBefore(r,i)})(document,'script','facebook-jssdk')";
39733      fb_root = document.createElement("div");
39734      fb_root.id = "fb-root";
39735      this.el.body.appendChild(fb_root);
39736      return this.el.body.appendChild(script);
39737    }
39738  };
39739
39740  Share.prototype.hook = function(type, network, instance) {
39741    var fn, opts;
39742    fn = this.config.networks[network][type];
39743    if (typeof fn === "function") {
39744      opts = fn.call(this.config.networks[network], instance);
39745      if (opts !== void 0) {
39746        opts = this.normalize_filter_config_updates(opts);
39747        this.extend(this.config.networks[network], opts, true);
39748        this.normalize_network_configuration();
39749      }
39750    }
39751  };
39752
39753  Share.prototype.default_title = function() {
39754    var content;
39755    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
39756      return encodeURIComponent(content.getAttribute('content'));
39757    } else if (content = document.querySelector('title')) {
39758      return encodeURIComponent(content.innerText);
39759    }
39760  };
39761
39762  Share.prototype.default_image = function() {
39763    var content;
39764    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
39765      return content.getAttribute('content');
39766    }
39767  };
39768
39769  Share.prototype.default_description = function() {
39770    var content;
39771    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
39772      return encodeURIComponent(content.getAttribute('content'));
39773    } else {
39774      return '';
39775    }
39776  };
39777
39778  Share.prototype.set_global_configuration = function() {
39779    var display, network, option, options, _ref, _results;
39780    _ref = this.config.networks;
39781    _results = [];
39782    for (network in _ref) {
39783      options = _ref[network];
39784      for (option in options) {
39785        if (this.config.networks[network][option] == null) {
39786          this.config.networks[network][option] = this.config[option];
39787        }
39788      }
39789      if (this.config.networks[network].enabled) {
39790        display = 'block';
39791        this.config.enabled_networks += 1;
39792      } else {
39793        display = 'none';
39794      }
39795      _results.push(this.config.networks[network].display = display);
39796    }
39797    return _results;
39798  };
39799
39800  Share.prototype.normalize_network_configuration = function() {
39801    if (!this.config.networks.facebook.app_id) {
39802      this.config.networks.facebook.load_sdk = false;
39803    }
39804    if (!this.is_encoded(this.config.networks.twitter.description)) {
39805      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
39806    }
39807    if (typeof this.config.networks.facebook.app_id === 'number') {
39808      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
39809    }
39810  };
39811
39812  Share.prototype.normalize_filter_config_updates = function(opts) {
39813    if (this.config.networks.facebook.app_id !== opts.app_id) {
39814      console.warn("You are unable to change the Facebook app_id after the button has been initialized. Please-in-out update your Facebook filters accordingly.");
39815      delete opts.app_id;
39816    }
39817    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
39818      console.warn("You are unable to change the Facebook load_sdk option after the button has been initialized. Please-in-out update your Facebook filters accordingly.");
39819      delete opts.app_id;
39820    }
39821    return opts;
39822  };
39823
39824  return Share;
39825
39826})(ShareUtils);
39827 return Share;
39828});
39829
39830// Generated by CoffeeScript 1.9.2
39831
39832// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
39833
39834(function() {
39835  var $, win;
39836
39837  $ = this.jQuery || window.jQuery;
39838
39839  win = $(window);
39840
39841  $.fn.stick_in_parent = function(opts) {
39842    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
39843    if (opts == null) {
39844      opts = {};
39845    }
39846    sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
39847    if (offset_top == null) {
39848      offset_top = 0;
39849    }
39850    if (parent_selector == null) {
39851      parent_selector = void 0;
39852    }
39853    if (inner_scrolling == null) {
39854      inner_scrolling = true;
39855    }
39856    if (sticky_class == null) {
39857      sticky_class = "is_stuck";
39858    }
39859    doc = $(document);
39860    if (enable_bottoming == null) {
39861      enable_bottoming = true;
39862    }
39863    outer_width = function(el) {
39864      var _el, computed, w;
39865      if (window.getComputedStyle) {
39866        _el = el[0];
39867        computed = window.getComputedStyle(el[0]);
39868        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
39869        if (computed.getPropertyValue("box-sizing") !== "border-box") {
39870          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
39871        }
39872        return w;
39873      } else {
39874        return el.outerWidth(true);
39875      }
39876    };
39877    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
39878      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
39879      if (elm.data("sticky_kit")) {
39880        return;
39881      }
39882      elm.data("sticky_kit", true);
39883      last_scroll_height = doc.height();
39884      parent = elm.parent();
39885      if (parent_selector != null) {
39886        parent = parent.closest(parent_selector);
39887      }
39888      if (!parent.length) {
39889        throw "failed to find stick parent";
39890      }
39891      fixed = false;
39892      bottomed = false;
39893      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
39894      if (spacer) {
39895        spacer.css('position', elm.css('position'));
39896      }
39897      recalc = function() {
39898        var border_top, padding_top, restore;
39899        if (detached) {
39900          return;
39901        }
39902        last_scroll_height = doc.height();
39903        border_top = parseInt(parent.css("border-top-width"), 10);
39904        padding_top = parseInt(parent.css("padding-top"), 10);
39905        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
39906        parent_top = parent.offset().top + border_top + padding_top;
39907        parent_height = parent.height();
39908        if (fixed) {
39909          fixed = false;
vendor: 6,068 bytes, lines 39910-40104
39910          bottomed = false;
39911          if (manual_spacer == null) {
39912            elm.insertAfter(spacer);
39913            spacer.detach();
39914          }
39915          elm.css({
39916            position: "",
39917            top: "",
39918            width: "",
39919            bottom: ""
39920          }).removeClass(sticky_class);
39921          restore = true;
39922        }
39923        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
39924        height = elm.outerHeight(true);
39925        el_float = elm.css("float");
39926        if (spacer) {
39927          spacer.css({
39928            width: outer_width(elm),
39929            height: height,
39930            display: elm.css("display"),
39931            "vertical-align": elm.css("vertical-align"),
39932            "float": el_float
39933          });
39934        }
39935        if (restore) {
39936          return tick();
39937        }
39938      };
39939      recalc();
39940      if (height === parent_height) {
39941        return;
39942      }
39943      last_pos = void 0;
39944      offset = offset_top;
39945      recalc_counter = recalc_every;
39946      tick = function() {
39947        var css, delta, recalced, scroll, will_bottom, win_height;
39948        if (detached) {
39949          return;
39950        }
39951        recalced = false;
39952        if (recalc_counter != null) {
39953          recalc_counter -= 1;
39954          if (recalc_counter <= 0) {
39955            recalc_counter = recalc_every;
39956            recalc();
39957            recalced = true;
39958          }
39959        }
39960        if (!recalced && doc.height() !== last_scroll_height) {
39961          recalc();
39962          recalced = true;
39963        }
39964        scroll = win.scrollTop();
39965        if (last_pos != null) {
39966          delta = scroll - last_pos;
39967        }
39968        last_pos = scroll;
39969        if (fixed) {
39970          if (enable_bottoming) {
39971            will_bottom = scroll + height + offset > parent_height + parent_top;
39972            if (bottomed && !will_bottom) {
39973              bottomed = false;
39974              elm.css({
39975                position: "fixed",
39976                bottom: "",
39977                top: offset
39978              }).trigger("sticky_kit:unbottom");
39979            }
39980          }
39981          if (scroll < top) {
39982            fixed = false;
39983            offset = offset_top;
39984            if (manual_spacer == null) {
39985              if (el_float === "left" || el_float === "right") {
39986                elm.insertAfter(spacer);
39987              }
39988              spacer.detach();
39989            }
39990            css = {
39991              position: "",
39992              width: "",
39993              top: ""
39994            };
39995            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
39996          }
39997          if (inner_scrolling) {
39998            win_height = win.height();
39999            if (height + offset_top > win_height) {
40000              if (!bottomed) {
40001                offset -= delta;
40002                offset = Math.max(win_height - height, offset);
40003                offset = Math.min(offset_top, offset);
40004                if (fixed) {
40005                  elm.css({
40006                    top: offset + "px"
40007                  });
40008                }
40009              }
40010            }
40011          }
40012        } else {
40013          if (scroll > top) {
40014            fixed = true;
40015            css = {
40016              position: "fixed",
40017              top: offset
40018            };
40019            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
40020            elm.css(css).addClass(sticky_class);
40021            if (manual_spacer == null) {
40022              elm.after(spacer);
40023              if (el_float === "left" || el_float === "right") {
40024                spacer.append(elm);
40025              }
40026            }
40027            elm.trigger("sticky_kit:stick");
40028          }
40029        }
40030        if (fixed && enable_bottoming) {
40031          if (will_bottom == null) {
40032            will_bottom = scroll + height + offset > parent_height + parent_top;
40033          }
40034          if (!bottomed && will_bottom) {
40035            bottomed = true;
40036            if (parent.css("position") === "static") {
40037              parent.css({
40038                position: "relative"
40039              });
40040            }
40041            return elm.css({
40042              position: "absolute",
40043              bottom: padding_bottom,
40044              top: "auto"
40045            }).trigger("sticky_kit:bottom");
40046          }
40047        }
40048      };
40049      recalc_and_tick = function() {
40050        recalc();
40051        return tick();
40052      };
40053      detach = function() {
40054        detached = true;
40055        win.off("touchmove", tick);
40056        win.off("scroll", tick);
40057        win.off("resize", recalc_and_tick);
40058        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
40059        elm.off("sticky_kit:detach", detach);
40060        elm.removeData("sticky_kit");
40061        elm.css({
40062          position: "",
40063          bottom: "",
40064          top: "",
40065          width: ""
40066        });
40067        parent.position("position", "");
40068        if (fixed) {
40069          if (manual_spacer == null) {
40070            if (el_float === "left" || el_float === "right") {
40071              elm.insertAfter(spacer);
40072            }
40073            spacer.remove();
40074          }
40075          return elm.removeClass(sticky_class);
40076        }
40077      };
40078      win.on("touchmove", tick);
40079      win.on("scroll", tick);
40080      win.on("resize", recalc_and_tick);
40081      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
40082      elm.on("sticky_kit:detach", detach);
40083      return setTimeout(tick, 0);
40084    };
40085    for (i = 0, len = this.length; i < len; i++) {
40086      elm = this[i];
40087      fn($(elm));
40088    }
40089    return this;
40090  };
40091
40092}).call(this);
40093/* ==========================================================================
40094 * bootstrap-tab-history.js
40095 * Author: Michael Narayan <[email protected]>
40096 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
40097 * ==========================================================================
40098 * Licensed under the Apache License, Version 2.0 (the "License"); you may
40099 * not use this file except in compliance with the License. You may obtain a
40100 * copy of the License at
40101 *
40102 * http://www.apache.org/licenses/LICENSE-2.0
40103 *
40104 * Unless required by applicable law or agreed to in writing, softw
40104are
40105 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
40106 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
40107 * License for the specific language governing permissions and limitations
40108 * under the License.
40109 * ========================================================================== */
40110
40111/* ========================================================================== */
40112/* JSHint directives                                                          */
40113/*                                                                            */
40114/* global BootstrapTabHistory: true                                           */
40115/*                                                                            */
40116/* global document                                                            */
40117/* global jQuery                                                              */
40118/* global history                                                             */
40119/* global window                                                              */
40120/* ========================================================================== */
40121
40122/**
40123 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
40124 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
40125 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
40126 *
40127 * See the README for additional information.
40128 *
40129 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
40130 */
40131
40132BootstrapTabHistory = {
40133  options: {
40134    /**
40135     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
40136     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
40137     *
40138     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
40139     *
40140     * @public
40141     * @type {?number}
40142     */
40143    defaultAnchorYOffset: 0,
40144    /**
40145     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
40146     *
40147     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
40148     *
40149     * @public
40150     * @type {string}
40151     */
40152    defaultChanger: 'replace',
40153    /**
40154     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
40155     * `null` is passed as the third parameter to these calls.
40156     *
40157     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
40158     *
40159     * @public
40160     * @type {boolean}
40161     */
40162    defaultUpdateURL: false,
40163    /**
40164     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
40165     * load.
40166     *
40167     * @public
40168     * @type {boolean}
40169     */
40170    showTabsBasedOnAnchor: true
40171  }
40172};
40173
40174(function () {
40175  'use strict';
40176
40177  jQuery(function () {
40178    if(history && history.pushState && history.replaceState) {
40179      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
40180
40181      if(bootstrapTabHistory) {
40182        showTabsBasedOnState(bootstrapTabHistory);
40183      } else {
40184        showTabsBasedOnAnchor();
40185      }
40186
40187      backfillHistoryState();
40188
40189      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
40190      jQuery(window).on('popstate', onPopState);
40191    } else {
40192      showTabsBasedOnAnchor();
40193    }
40194  });
40195
40196  /**
40197   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
40198   *
40199   * @type {boolean}
40200   */
40201  var showingTabsBasedOnState = false;
40202
40203  /**
40204   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
40205   * `history.back` handling when `data-tab-history-update-url` is true.
40206   */
40207  function backfillHistoryState() {
40208    var newState = null;
40209
40210    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
40211      var $activeTabElement = jQuery(this);
40212      var selector = getTabSelector($activeTabElement);
40213
40214      if(selector) {
40215        var tabGroup = getTabGroup($activeTabElement);
40216
40217        if(tabGroup) {
40218          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
40219        }
40220      }
40221    });
40222
40223    if(newState) {
40224      history.replaceState(newState, '', null);
40225    }
40226  }
40227
40228  /**
40229   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
40230   * said bootstrapTabHistory attribute.
40231   *
40232   * @param {?object} existingState
40233   * @param {!string} tabGroup
40234   * @param {!string} selector
40235   * @returns {!object}
40236   */
40237  function createNewHistoryState(existingState, tabGroup, selector) {
40238    // Clone history.state and ensure it has a bootstrapTabHistory entry.
40239    var newState = jQuery.extend(true, {}, existingState, {
40240      bootstrapTabHistory: {}
40241    });
40242
40243    newState.bootstrapTabHistory[tabGroup] = selector;
40244
40245    return newState;
40246  }
40247
40248  /**
40249   * @param {jQuery} $tab
40250   * @returns {?string}
40251   */
40252  function getTabGroup($tab) {
40253    return parseTruthyAttributeValue($tab.data('tab-history'));
40254  }
40255
40256  /**
40257   * @param {jQuery} $tab
40258   * @returns {?string}
40259   */
40260  function getTabSelector($tab) {
40261    return $tab.data('target') || $tab.attr('href');
40262  }
40263
40264  /**
40265   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
40266   *
40267   * @param {jQuery.Event} shownEvt
40268   */
40269  function onShownTab(shownEvt) {
40270    if(!showingTabsBasedOnState) {
40271      var $activatedTab = jQuery(shownEvt.target);
40272      if ( $activatedTab.hasClass('panel-collapse') )
40273        $activatedTab = $activatedTab.closest('.panel').find('a');
40274      var selector = getTabSelector($activatedTab);
40275
40276      if(selector) {
40277        var tabGroup = getTabGroup($activatedTab);
40278
40279        if(tabGroup) {
40280          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
40281          var newState = createNewHistoryState(history.state, tabGroup, selector);
40282          var updateURL = (function ($activatedTab) {
40283            if(selector[0] === '#') {
40284              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
40285
40286              if(elementUpdateURLOption === undefined) {
40287                return BootstrapTabHistory.options.defaultUpdateURL;
40288              } else {
40289                return elementUpdateURLOption;
40290              }
40291            } else {
40292              return false;
40293            }
40294          })($activatedTab);
40295
40296          switch(historyChanger) {
40297            case 'push':
40298              history.pushState(newState, '', updateURL ? selector : null);
40299              break;
40300            case 'replace':
40301              history.replaceState(newState, '', updateURL ? selector : null);
40302              break;
40303            default:
40304              throw new Error('Unknown tab-history-changer: ' + historyChanger);
40305          }
40306        }
40307      }
40308    }
40309  }
40310
40311  /**
40312   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
40313   */
40314  function onPopState() {
40315    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
40316
40317    if(bootstrapTabHistory) {
40318      showTabsBasedOnState(bootstrapTabHistory);
40319    }
40320  }
40321
40322  /**
40323   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
40324   *
40325   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
40326   *
40327   * @param {*} value
40328   * @returns {*}
40329   */
40330  function parseTruthyAttributeValue(value) {
40331    if(value) {
40332      return value;
40333    } else if(value === '') {
40334      return true;
40335    } else {
40336      return value;
40337    }
40338  }
40339
40340  /**
40341   * Show tabs based upon the anchor component of `window.location`.
40342   */
40343  function showTabsBasedOnAnchor() {
40344    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
40345      var anchor = window.location && window.location.hash;
40346
40347      if(anchor) {
40348        var $tabElement = showTabForSelector(anchor);
40349
40350        if($tabElement && window.addEventListener && window.removeEventListener) {
40351          var anchorYOffset = (function ($tabElement) {
40352            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
40353
40354            if(elementSetting === undefined) {
40355              return BootstrapTabHistory.options.defaultAnchorYOffset;
40356            } else {
40357              return elementSetting;
40358            }
40359          })($tabElement);
40360
40361          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
40362          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
40363          //   `history.state` object should have been used (unless the browser did not support the modern History API).
40364          if(anchorYOffset || anchorYOffset === 0) {
40365            var scrollListener = function resetAnchorScroll () {
40366              window.removeEventListener('scroll', scrollListener);
40367              window.scrollTo(0, anchorYOffset);
40368            };
40369
40370            window.addEventListener('scroll', scrollListener);
40371          }
40372        }
40373      }
40374    }
40375  }
40376
40377  /**
40378   * Show a tab which corresponds to the provided selector.
40379   *
40380   * @param {string} selector - A CSS selector.
40381   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
40382   */
40383  function showTabForSelector(selector) {
40384    var $tabElement = (function (selector) {
40385      var $ret = null;
40386
40387      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
40388        var $potentialTab = jQuery(this);
40389
40390        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
40391          $ret = $potentialTab;
40392          return false;
vendor: 43,483 bytes, lines 40393-41609
40393        } else {
40394         return null;
40395        }
40396      });
40397
40398      return $ret;
40399    })(selector);
40400
40401    if($tabElement) {
40402      if ( !$tabElement.parent().hasClass('active') ) {
40403        $tabElement.trigger('click');
40404      }
40405      //$tabElement.tab('show');
40406    }
40407
40408    return $tabElement;
40409  }
40410
40411  /**
40412   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
40413   *
40414   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
40415   */
40416  function showTabsBasedOnState(bootstrapTabHistory) {
40417    showingTabsBasedOnState = true;
40418
40419    try {
40420      for(var k in bootstrapTabHistory) {
40421        if(bootstrapTabHistory.hasOwnProperty(k)) {
40422          showTabForSelector(bootstrapTabHistory[k]);
40423        }
40424      }
40425    } finally {
40426      showingTabsBasedOnState = false;
40427    }
40428  }
40429})();
40430
40431/*!
40432 * justifiedGallery - v3.8.1
40433 * http://miromannino.github.io/Justified-Gallery/
40434 * Copyright (c) 2020 Miro Mannino
40435 * Licensed under the MIT license.
40436 */
40437(function (factory) {
40438  if (typeof define === 'function' && define.amd) {
40439    // AMD. Register as an anonymous module.
40440    define(['jquery'], factory);
40441  } else if (typeof module === 'object' && module.exports) {
40442    // Node/CommonJS
40443    module.exports = function (root, jQuery) {
40444      if (jQuery === undefined) {
40445        // require('jQuery') returns a factory that requires window to
40446        // build a jQuery instance, we normalize how we use modules
40447        // that require this pattern but the window provided is a noop
40448        // if it's defined (how jquery works)
40449        if (typeof window !== 'undefined') {
40450          jQuery = require('jquery');
40451        }
40452        else {
40453          jQuery = require('jquery')(root);
40454        }
40455      }
40456      factory(jQuery);
40457      return jQuery;
40458    };
40459  } else {
40460    // Browser globals
40461    factory(jQuery);
40462  }
40463}(function ($) {
40464
40465  /**
40466   * Justified Gallery controller constructor
40467   *
40468   * @param $gallery the gallery to build
40469   * @param settings the settings (the defaults are in JustifiedGallery.defaults)
40470   * @constructor
40471   */
40472  var JustifiedGallery = function ($gallery, settings) {
40473
40474    this.settings = settings;
40475    this.checkSettings();
40476
40477    this.imgAnalyzerTimeout = null;
40478    this.entries = null;
40479    this.buildingRow = {
40480      entriesBuff: [],
40481      width: 0,
40482      height: 0,
40483      aspectRatio: 0
40484    };
40485    this.lastFetchedEntry = null;
40486    this.lastAnalyzedIndex = -1;
40487    this.yield = {
40488      every: 2, // do a flush every n flushes (must be greater than 1)
40489      flushed: 0 // flushed rows without a yield
40490    };
40491    this.border = settings.border >= 0 ? settings.border : settings.margins;
40492    this.maxRowHeight = this.retrieveMaxRowHeight();
40493    this.suffixRanges = this.retrieveSuffixRanges();
40494    this.offY = this.border;
40495    this.rows = 0;
40496    this.spinner = {
40497      phase: 0,
40498      timeSlot: 150,
40499      $el: $('<div class="jg-spinner"><span></span><span></span><span></span></div>'),
40500      intervalId: null
40501    };
40502    this.scrollBarOn = false;
40503    this.checkWidthIntervalId = null;
40504    this.galleryWidth = $gallery.width();
40505    this.$gallery = $gallery;
40506
40507  };
40508
40509  /** @returns {String} the best suffix given the width and the height */
40510  JustifiedGallery.prototype.getSuffix = function (width, height) {
40511    var longestSide, i;
40512    longestSide = (width > height) ? width : height;
40513    for (i = 0; i < this.suffixRanges.length; i++) {
40514      if (longestSide <= this.suffixRanges[i]) {
40515        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
40516      }
40517    }
40518    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
40519  };
40520
40521  /**
40522   * Remove the suffix from the string
40523   *
40524   * @returns {string} a new string without the suffix
40525   */
40526  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
40527    return str.substring(0, str.length - suffix.length);
40528  };
40529
40530  /**
40531   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
40532   */
40533  JustifiedGallery.prototype.endsWith = function (str, suffix) {
40534    return str.indexOf(suffix, str.length - suffix.length) !== -1;
40535  };
40536
40537  /**
40538   * Get the used suffix of a particular url
40539   *
40540   * @param str
40541   * @returns {String} return the used suffix
40542   */
40543  JustifiedGallery.prototype.getUsedSuffix = function (str) {
40544    for (var si in this.settings.sizeRangeSuffixes) {
40545      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
40546        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
40547        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
40548      }
40549    }
40550    return '';
40551  };
40552
40553  /**
40554   * Given an image src, with the width and the height, returns the new image src with the
40555   * best suffix to show the best quality thumbnail.
40556   *
40557   * @returns {String} the suffix to use
40558   */
40559  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
40560    var newImageSrc;
40561
40562    if (this.settings.thumbnailPath) {
40563      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
40564    } else {
40565      var matchRes = imageSrc.match(this.settings.extension);
40566      var ext = (matchRes !== null) ? matchRes[0] : '';
40567      newImageSrc = imageSrc.replace(this.settings.extension, '');
40568      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
40569      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
40570    }
40571
40572    return newImageSrc;
40573  };
40574
40575  /**
40576   * Shows the images that is in the given entry
40577   *
40578   * @param $entry the entry
40579   * @param callback the callback that is called when the show animation is finished
40580   */
40581  JustifiedGallery.prototype.showImg = function ($entry, callback) {
40582    if (this.settings.cssAnimation) {
40583      $entry.addClass('jg-entry-visible');
40584      if (callback) callback();
40585    } else {
40586      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
40587      $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
40588    }
40589  };
40590
40591  /**
40592   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
40593   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
40594   *
40595   * @param $image the image to analyze
40596   * @returns {String} the extracted src
40597   */
40598  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
40599    var imageSrc = $image.data('safe-src');
40600    var imageSrcLoc = 'data-safe-src';
40601    // Begin Uncode edit
40602    if (typeof imageSrc === 'undefined') {
40603    	var imageCurrentSrc = $image[0].currentSrc;
40604    	if (imageCurrentSrc) {
40605    		imageSrc = imageCurrentSrc;
40606    	} else {
40607    		imageSrc = $image.attr('src');
40608    	}
40609		imageSrcLoc = 'src';
40610    }
40611    // End Uncode edit
40612    $image.data('jg.originalSrc', imageSrc); // this is saved for the destroy method
40613    $image.data('jg.src', imageSrc); // this will change overtime
40614    $image.data('jg.originalSrcLoc', imageSrcLoc); // this is saved for the destroy method
40615    return imageSrc;
40616  };
40617
40618  /** @returns {jQuery} the image in the given entry */
40619  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
40620    var $img = $entry.find(this.settings.imgSelector);
40621    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
40622    return $img.length === 0 ? null : $img;
40623  };
40624
40625  /** @returns {jQuery} the caption in the given entry */
40626  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
40627    var $caption = $entry.find('> .jg-caption');
40628    return $caption.length === 0 ? null : $caption;
40629  };
40630
40631  /**
40632   * Display the entry
40633   *
40634   * @param {jQuery} $entry the entry to display
40635   * @param {int} x the x position where the entry must be positioned
40636   * @param y the y position where the entry must be positioned
40637   * @param imgWidth the image width
40638   * @param imgHeight the image height
40639   * @param rowHeight the row height of the row that owns the entry
40640   */
40641  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
40642    $entry.width(imgWidth);
40643    $entry.height(Math.floor(rowHeight));//hacked by Uncode
40644    $entry.css('top', Math.floor(y));//hacked by Uncode
40645    $entry.css('left', x);
40646
40647    var $image = this.imgFromEntry($entry);
40648    if ($image !== null) {
40649      $image.css('width', imgWidth);
40650      $image.css('height', imgHeight);
40651      $image.css('margin-left', - imgWidth / 2);
40652      $image.css('margin-top', - imgHeight / 2);
40653
40654      // Image reloading for an high quality of thumbnails
40655      var imageSrc = $image.data('jg.src');
40656      if (imageSrc) {
40657        imageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
40658
40659        $image.one('error', function () {
40660           this.resetImgSrc($image); //revert to the original thumbnail
40661        });
40662
40663        var loadNewImage = function () {
40664          // if (imageSrc !== newImageSrc) {
40665            $image.attr('src', imageSrc);
40666          // }
40667        };
40668
40669        if ($entry.data('jg.loaded') === 'skipped' && imageSrc) {
40670          this.onImageEvent(imageSrc, (function() {
40671            this.showImg($entry, loadNewImage); //load the new image after the fadeIn
40672            $entry.data('jg.loaded', true);
40673          }).bind(this));
40674        } else {
40675          this.showImg($entry, loadNewImage); //load the new image after the fadeIn
40676        }
40677
40678      }
40679
40680    } else {
40681      this.showImg($entry);
40682    }
40683
40684    this.displayEntryCaption($entry);
40685  };
40686
40687  /**
40688   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
40689   * or the 'title' attributes.
40690   *
40691   * @param {jQuery} $entry the entry to process
40692   */
40693  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
40694    var $image = this.imgFromEntry($entry);
40695    if ($image !== null && this.settings.captions) {
40696      var $imgCaption = this.captionFromEntry($entry);
40697
40698      // Create it if it doesn't exists
40699      if ($imgCaption === null) {
40700        var caption = $image.attr('alt');
40701        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
40702        if (this.isValidCaption(caption)) { // Create only we found something
40703          $imgCaption = $('<div class="jg-caption">' + caption + '</div>');
40704          $entry.append($imgCaption);
40705          $entry.data('jg.createdCaption', true);
40706        }
40707      }
40708
40709      // Create events (we check again the $imgCaption because it can be still inexistent)
40710      if ($imgCaption !== null) {
40711        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
40712        this.addCaptionEventsHandlers($entry);
40713      }
40714    } else {
40715      this.removeCaptionEventsHandlers($entry);
40716    }
40717  };
40718
40719  /**
40720   * Validates the caption
40721   *
40722   * @param caption The caption that should be validated
40723   * @return {boolean} Validation result
40724   */
40725  JustifiedGallery.prototype.isValidCaption = function (caption) {
40726    return (typeof caption !== 'undefined' && caption.length > 0);
40727  };
40728
40729  /**
40730   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
40731   * It shows the caption using jQuery (or using CSS if it is configured so)
40732   *
40733   * @param {Event} eventObject the event object
40734   */
40735  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
40736    var $caption = this.captionFromEntry($(eventObject.currentTarget));
40737    if (this.settings.cssAnimation) {
40738      $caption.addClass('jg-caption-visible').removeClass('jg-caption-hidden');
40739    } else {
40740      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
40741        this.settings.captionSettings.visibleOpacity);
40742    }
40743  };
40744
40745  /**
40746   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
40747   * It hides the caption using jQuery (or using CSS if it is configured so)
40748   *
40749   * @param {Event} eventObject the event object
40750   */
40751  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
40752    var $caption = this.captionFromEntry($(eventObject.currentTarget));
40753    if (this.settings.cssAnimation) {
40754      $caption.removeClass('jg-caption-visible').removeClass('jg-caption-hidden');
40755    } else {
40756      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
40757        this.settings.captionSettings.nonVisibleOpacity);
40758    }
40759  };
40760
40761  /**
40762   * Add the handlers of the entry for the caption
40763   *
40764   * @param $entry the entry to modify
40765   */
40766  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
40767    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
40768    if (typeof captionMouseEvents === 'undefined') {
40769      captionMouseEvents = {
40770        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
40771        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
40772      };
40773      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
40774      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
40775      $entry.data('jg.captionMouseEvents', captionMouseEvents);
40776    }
40777  };
40778
40779  /**
40780   * Remove the handlers of the entry for the caption
40781   *
40782   * @param $entry the entry to modify
40783   */
40784  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
40785    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
40786    if (typeof captionMouseEvents !== 'undefined') {
40787      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
40788      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
40789      $entry.removeData('jg.captionMouseEvents');
40790    }
40791  };
40792
40793  /**
40794   * Clear the building row data to be used for a new row
40795   */
40796  JustifiedGallery.prototype.clearBuildingRow = function () {
40797    this.buildingRow.entriesBuff = [];
40798    this.buildingRow.aspectRatio = 0;
40799    this.buildingRow.width = 0;
40800  };
40801
40802  /**
40803   * Justify the building row, preparing it to
40804   *
40805   * @param isLastRow
40806   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
40807   * @returns a boolean to know if the row has been justified or not
40808   */
40809  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow, hiddenRow) {
40810    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
40811    var minHeight = 0;
40812    var availableWidth = this.galleryWidth - 2 * this.border - (
40813      (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
40814    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
40815    var defaultRowHeight = this.settings.rowHeight;
40816    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
40817
40818    //Skip the last row if we can't justify it and the lastRow == 'hide'
40819    if (hiddenRow || (isLastRow && this.settings.lastRow === 'hide' && !justifiable)) {
40820      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
40821        $entry = this.buildingRow.entriesBuff[i];
40822        if (this.settings.cssAnimation)
40823          $entry.removeClass('jg-entry-visible');
40824        else {
40825          $entry.stop().fadeTo(0, 0.1);
40826          $entry.find('> img, > a > img').fadeTo(0, 0);
40827        }
40828      }
40829      return -1;
40830    }
40831
40832    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
40833    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
40834      justify = false;
40835
40836      if (this.rows > 0) {
40837        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
40838        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
40839      }
40840    }
40841
40842    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
40843      $entry = this.buildingRow.entriesBuff[i];
40844      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
40845
40846      if (justify) {
40847        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
40848        newImgH = rowHeight;
40849      } else {
40850        newImgW = defaultRowHeight * imgAspectRatio;
40851        newImgH = defaultRowHeight;
40852      }
40853
40854      availableWidth -= Math.round(newImgW);
40855      $entry.data('jg.jwidth', Math.round(newImgW));
40856      $entry.data('jg.jheight', Math.ceil(newImgH));
40857      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
40858    }
40859
40860    this.buildingRow.height = minHeight;
40861    return justify;
40862  };
40863
40864  /**
40865   * Flush a row: justify it, modify the gallery height accordingly to the row height
40866   *
40867   * @param isLastRow
40868   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
40869   */
40870  JustifiedGallery.prototype.flushRow = function (isLastRow, hiddenRow) {
40871    var settings = this.settings;
40872    var $entry, buildingRowRes, offX = this.border, i;
40873
40874    buildingRowRes = this.prepareBuildingRow(isLastRow, hiddenRow);
40875    if (hiddenRow || (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1)) {
40876      this.clearBuildingRow();
40877      return;
40878    }
40879
40880    if (this.maxRowHeight) {
40881      if (this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight;
40882    }
40883
40884    //Align last (unjustified) row
40885    if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) {
40886      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
40887
40888      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
40889        $entry = this.buildingRow.entriesBuff[i];
40890        availableWidth -= $entry.data('jg.jwidth');
40891      }
40892
40893      if (settings.lastRow === 'center')
40894        offX += Math.round(availableWidth / 2);
40895      else if (settings.lastRow === 'right')
40896        offX += availableWidth;
40897    }
40898
40899    var lastEntryIdx = this.buildingRow.entriesBuff.length - 1;
40900    for (i = 0; i <= lastEntryIdx; i++) {
40901      $entry = this.buildingRow.entriesBuff[this.settings.rtl ? lastEntryIdx - i : i];
40902      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
40903      offX += $entry.data('jg.jwidth') + settings.margins;
40904    }
40905
40906    //Gallery Height
40907    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
40908    this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight());
40909
40910    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
40911      //Ready for a new row
40912      this.offY += this.buildingRow.height + settings.margins;
40913      this.rows += 1;
40914      this.clearBuildingRow();
40915      this.settings.triggerEvent.call(this, 'jg.rowflush');
40916    }
40917  };
40918
40919
40920  // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221
40921  var galleryPrevStaticHeight = 0;
40922
40923  JustifiedGallery.prototype.rememberGalleryHeight = function () {
40924    galleryPrevStaticHeight = this.$gallery.height();
40925    this.$gallery.height(galleryPrevStaticHeight);
40926  };
40927
40928  // grow only
40929  JustifiedGallery.prototype.setGalleryTempHeight = function (height) {
40930    galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight);
40931    this.$gallery.height(galleryPrevStaticHeight);
40932  };
40933
40934  JustifiedGallery.prototype.setGalleryFinalHeight = function (height) {
40935    galleryPrevStaticHeight = height;
40936    this.$gallery.height(height);
40937  };
40938
40939  /**
40940   * Checks the width of the gallery container, to know if a new justification is needed
40941   */
40942  JustifiedGallery.prototype.checkWidth = function () {
40943    this.checkWidthIntervalId = setInterval($.proxy(function () {
40944
40945      // if the gallery is not currently visible, abort.
40946      if (!this.$gallery.is(":visible")) return;
40947
40948      var galleryWidth = parseFloat(this.$gallery.width());
40949      if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
40950        this.galleryWidth = galleryWidth;
40951        this.rewind();
40952
40953        this.rememberGalleryHeight();
40954
40955        // Restart to analyze
40956        this.startImgAnalyzer(true);
40957      }
40958    }, this), this.settings.refreshTime);
40959  };
40960
40961  /**
40962   * @returns {boolean} a boolean saying if the spinner is active or not
40963   */
40964  JustifiedGallery.prototype.isSpinnerActive = function () {
40965    return this.spinner.intervalId !== null;
40966  };
40967
40968  /**
40969   * @returns {int} the spinner height
40970   */
40971  JustifiedGallery.prototype.getSpinnerHeight = function () {
40972    return this.spinner.$el.innerHeight();
40973  };
40974
40975  /**
40976   * Stops the spinner animation and modify the gallery height to exclude the spinner
40977   */
40978  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
40979    clearInterval(this.spinner.intervalId);
40980    this.spinner.intervalId = null;
40981    this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight());
40982    this.spinner.$el.detach();
40983  };
40984
40985  /**
40986   * Starts the spinner animation
40987   */
40988  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
40989    var spinnerContext = this.spinner;
40990    var $spinnerPoints = spinnerContext.$el.find('span');
40991    clearInterval(spinnerContext.intervalId);
40992    this.$gallery.append(spinnerContext.$el);
40993    this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight());
40994    spinnerContext.intervalId = setInterval(function () {
40995      if (spinnerContext.phase < $spinnerPoints.length) {
40996        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
40997      } else {
40998        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
40999      }
41000      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
41001    }, spinnerContext.timeSlot);
41002  };
41003
41004  /**
41005   * Rewind the image analysis to start from the first entry.
41006   */
41007  JustifiedGallery.prototype.rewind = function () {
41008    this.lastFetchedEntry = null;
41009    this.lastAnalyzedIndex = -1;
41010    this.offY = this.border;
41011    this.rows = 0;
41012    this.clearBuildingRow();
41013  };
41014
41015  /**
41016   * @returns {String} `settings.selector` rejecting spinner element
41017   */
41018  JustifiedGallery.prototype.getSelectorWithoutSpinner = function () {
41019    return this.settings.selector + ', div:not(.jg-spinner)';
41020  };
41021
41022  /**
41023   * @returns {Array} all entries matched by `settings.selector`
41024   */
41025  JustifiedGallery.prototype.getAllEntries = function () {
41026    var selector = this.getSelectorWithoutSpinner();
41027    return this.$gallery.children(selector).toArray();
41028  };
41029
41030  /**
41031   * Update the entries searching it from the justified gallery HTML element
41032   *
41033   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
41034   * @returns {boolean} true if some entries has been founded
41035   */
41036  JustifiedGallery.prototype.updateEntries = function (norewind) {
41037    var newEntries;
41038
41039    if (norewind && this.lastFetchedEntry != null) {
41040      var selector = this.getSelectorWithoutSpinner();
41041      newEntries = $(this.lastFetchedEntry).nextAll(selector).toArray();
41042    } else {
41043      this.entries = [];
41044      newEntries = this.getAllEntries();
41045    }
41046
41047    if (newEntries.length > 0) {
41048
41049      // Sort or randomize
41050      if ($.isFunction(this.settings.sort)) {
41051        newEntries = this.sortArray(newEntries);
41052      } else if (this.settings.randomize) {
41053        newEntries = this.shuffleArray(newEntries);
41054      }
41055      this.lastFetchedEntry = newEntries[newEntries.length - 1];
41056
41057      // Filter
41058      if (this.settings.filter) {
41059        newEntries = this.filterArray(newEntries);
41060      } else {
41061        this.resetFilters(newEntries);
41062      }
41063
41064    }
41065
41066    this.entries = this.entries.concat(newEntries);
41067    return true;
41068  };
41069
41070  /**
41071   * Apply the entries order to the DOM, iterating the entries and appending the images
41072   *
41073   * @param entries the entries that has been modified and that must be re-ordered in the DOM
41074   */
41075  JustifiedGallery.prototype.insertToGallery = function (entries) {
41076    var that = this;
41077    $.each(entries, function () {
41078      $(this).appendTo(that.$gallery);
41079    });
41080  };
41081
41082  /**
41083   * Shuffle the array using the Fisher-Yates shuffle algorithm
41084   *
41085   * @param a the array to shuffle
41086   * @return the shuffled array
41087   */
41088  JustifiedGallery.prototype.shuffleArray = function (a) {
41089    var i, j, temp;
41090    for (i = a.length - 1; i > 0; i--) {
41091      j = Math.floor(Math.random() * (i + 1));
41092      temp = a[i];
41093      a[i] = a[j];
41094      a[j] = temp;
41095    }
41096    this.insertToGallery(a);
41097    return a;
41098  };
41099
41100  /**
41101   * Sort the array using settings.comparator as comparator
41102   *
41103   * @param a the array to sort (it is sorted)
41104   * @return the sorted array
41105   */
41106  JustifiedGallery.prototype.sortArray = function (a) {
41107    a.sort(this.settings.sort);
41108    this.insertToGallery(a);
41109    return a;
41110  };
41111
41112  /**
41113   * Reset the filters removing the 'jg-filtered' class from all the entries
41114   *
41115   * @param a the array to reset
41116   */
41117  JustifiedGallery.prototype.resetFilters = function (a) {
41118    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
41119  };
41120
41121  /**
41122   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
41123   *
41124   * @param a the array to filter
41125   * @return the filtered array
41126   */
41127  JustifiedGallery.prototype.filterArray = function (a) {
41128    var settings = this.settings;
41129    if ($.type(settings.filter) === 'string') {
41130      // Filter only keeping the entries passed in the string
41131      return a.filter(function (el) {
41132        var $el = $(el);
41133        if ($el.is(settings.filter)) {
41134          $el.removeClass('jg-filtered');
41135          return true;
41136        } else {
41137          $el.addClass('jg-filtered').removeClass('jg-visible');
41138          return false;
41139        }
41140      });
41141    } else if ($.isFunction(settings.filter)) {
41142      // Filter using the passed function
41143      var filteredArr = a.filter(settings.filter);
41144      for (var i = 0; i < a.length; i++) {
41145        if (filteredArr.indexOf(a[i]) === -1) {
41146          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
41147        } else {
41148          $(a[i]).removeClass('jg-filtered');
41149        }
41150      }
41151      return filteredArr;
41152    }
41153  };
41154
41155  /**
41156   * Revert the image src to the default value.
41157   */
41158  JustifiedGallery.prototype.resetImgSrc = function ($img) {
41159    if ($img.data('jg.originalSrcLoc') === 'src') {
41160      $img.attr('src', $img.data('jg.originalSrc'));
41161    } else {
41162      $img.attr('src', '');
41163    }
41164  };
41165
41166  /**
41167   * Destroy the Justified Gallery instance.
41168   *
41169   * It clears all the css properties added in the style attributes. We doesn't backup the original
41170   * values for those css attributes, because it costs (performance) and because in general one
41171   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
41172   * classes). Creating a backup is also difficult because JG could be called multiple times and
41173   * with different style attributes.
41174   */
41175  JustifiedGallery.prototype.destroy = function () {
41176    clearInterval(this.checkWidthIntervalId);
41177    this.stopImgAnalyzerStarter();
41178
41179    // Get fresh entries list since filtered entries are absent in `this.entries`
41180    $.each(this.getAllEntries(), $.proxy(function (_, entry) {
41181      var $entry = $(entry);
41182
41183      // Reset entry style
41184      $entry.css('width', '');
41185      $entry.css('height', '');
41186      $entry.css('top', '');
41187      $entry.css('left', '');
41188      $entry.data('jg.loaded', undefined);
41189      $entry.removeClass('jg-entry jg-filtered jg-entry-visible');
41190
41191      // Reset image style
41192      var $img = this.imgFromEntry($entry);
41193      if ($img) {
41194        $img.css('width', '');
41195        $img.css('height', '');
41196        $img.css('margin-left', '');
41197        $img.css('margin-top', '');
41198        this.resetImgSrc($img);
41199        $img.data('jg.originalSrc', undefined);
41200        $img.data('jg.originalSrcLoc', undefined);
41201        $img.data('jg.src', undefined);
41202      }
41203
41204      // Remove caption
41205      this.removeCaptionEventsHandlers($entry);
41206      var $caption = this.captionFromEntry($entry);
41207      if ($entry.data('jg.createdCaption')) {
41208        // remove also the caption element (if created by jg)
41209        $entry.data('jg.createdCaption', undefined);
41210        if ($caption !== null) $caption.remove();
41211      } else {
41212        if ($caption !== null) $caption.fadeTo(0, 1);
41213      }
41214
41215    }, this));
41216
41217    this.$gallery.css('height', '');
41218    this.$gallery.removeClass('justified-gallery');
41219    this.$gallery.data('jg.controller', undefined);
41220    this.settings.triggerEvent.call(this, 'jg.destroy');
41221  };
41222
41223  /**
41224   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
41225   *
41226   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
41227   */
41228  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
41229    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
41230      var $entry = $(this.entries[i]);
41231      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
41232        var availableWidth = this.galleryWidth - 2 * this.border - (
41233          (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
41234        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
41235
41236        this.buildingRow.entriesBuff.push($entry);
41237        this.buildingRow.aspectRatio += imgAspectRatio;
41238        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
41239        this.lastAnalyzedIndex = i;
41240
41241        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
41242          this.flushRow(false, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
41243
41244          if (++this.yield.flushed >= this.yield.every) {
41245            this.startImgAnalyzer(isForResize);
41246            return;
41247          }
41248        }
41249      } else if ($entry.data('jg.loaded') !== 'error') {
41250        return;
41251      }
41252    }
41253
41254    // Last row flush (the row is not full)
41255    if (this.buildingRow.entriesBuff.length > 0) {
41256      this.flushRow(true, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
41257    }
41258
41259    if (this.isSpinnerActive()) {
41260      this.stopLoadingSpinnerAnimation();
41261    }
41262
41263    /* Stop, if there is, the timeout to start the analyzeImages.
41264     This is because an image can be set loaded, and the timeout can be set,
41265     but this image can be analyzed yet.
41266     */
41267    this.stopImgAnalyzerStarter();
41268
41269    this.setGalleryFinalHeight(this.galleryHeightToSet);
41270
41271    //On complete callback
41272    this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete');
41273  };
41274
41275  /**
41276   * Stops any ImgAnalyzer starter (that has an assigned timeout)
41277   */
41278  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
41279    this.yield.flushed = 0;
41280    if (this.imgAnalyzerTimeout !== null) {
41281      clearTimeout(this.imgAnalyzerTimeout);
41282      this.imgAnalyzerTimeout = null;
41283    }
41284  };
41285
41286  /**
41287   * Starts the image analyzer. It is not immediately called to let the browser to update the view
41288   *
41289   * @param isForResize specifies if the image analyzer must be called for resizing or not
41290   */
41291  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
41292    var that = this;
41293    this.stopImgAnalyzerStarter();
41294    this.imgAnalyzerTimeout = setTimeout(function () {
41295      that.analyzeImages(isForResize);
41296    }, 0.001); // we can't start it immediately due to a IE different behaviour
41297  };
41298
41299  /**
41300   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
41301   * because some browsers, with a 404 set complete = true.
41302   *
41303   * @param imageSrc the image src to load
41304   * @param onLoad callback that is called when the image has been loaded
41305   * @param onError callback that is called in case of an error
41306   */
41307  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
41308    if (!onLoad && !onError) return;
41309
41310    var memImage = new Image();
41311    var $memImage = $(memImage);
41312    if (onLoad) {
41313      $memImage.one('load', function () {
41314        $memImage.off('load error');
41315        onLoad(memImage);
41316      });
41317    }
41318    if (onError) {
41319      $memImage.one('error', function () {
41320        $memImage.off('load error');
41321        onError(memImage);
41322      });
41323    }
41324    memImage.src = imageSrc;
41325  };
41326
41327  /**
41328   * Init of Justified Gallery controlled
41329   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
41330   */
41331  JustifiedGallery.prototype.init = function () {
41332    var imagesToLoad = false, skippedImages = false, that = this;
41333    $.each(this.entries, function (index, entry) {
41334      var $entry = $(entry);
41335      var $image = that.imgFromEntry($entry);
41336
41337      $entry.addClass('jg-entry');
41338
41339      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
41340
41341        // Link Rel global overwrite
41342        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
41343
41344        // Link Target global overwrite
41345        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
41346
41347        if ($image !== null) {
41348
41349          // Image src
41350          var imageSrc = that.extractImgSrcFromImage($image);
41351
41352          /* If we have the height and the width, we don't wait that the image is loaded,
41353             but we start directly with the justification */
41354          if (that.settings.waitThumbnailsLoad === false || !imageSrc) {
41355            var width = parseFloat($image.attr('width'));
41356            var height = parseFloat($image.attr('height'));
41357            if ($image.prop('tagName') === 'svg') {
41358              width = parseFloat($image[0].getBBox().width);
41359              height = parseFloat($image[0].getBBox().height);
41360            }
41361            if (!isNaN(width) && !isNaN(height)) {
41362              $entry.data('jg.width', width);
41363              $entry.data('jg.height', height);
41364              $entry.data('jg.loaded', 'skipped');
41365              skippedImages = true;
41366              that.startImgAnalyzer(false);
41367              return true; // continue
41368            }
41369          }
41370
41371          $entry.data('jg.loaded', false);
41372          imagesToLoad = true;
41373
41374          // Spinner start
41375          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
41376
41377          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
41378            $entry.data('jg.width', loadImg.width);
41379            $entry.data('jg.height', loadImg.height);
41380            $entry.data('jg.loaded', true);
41381            that.startImgAnalyzer(false);
41382          }, function () { // image load error
41383            $entry.data('jg.loaded', 'error');
41384            that.startImgAnalyzer(false);
41385          });
41386
41387        } else {
41388          $entry.data('jg.loaded', true);
41389          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
41390          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
41391        }
41392
41393      }
41394
41395    });
41396
41397    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
41398    this.checkWidth();
41399  };
41400
41401  /**
41402   * Checks that it is a valid number. If a string is passed it is converted to a number
41403   *
41404   * @param settingContainer the object that contains the setting (to allow the conversion)
41405   * @param settingName the setting name
41406   */
41407  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
41408    if ($.type(settingContainer[settingName]) === 'string') {
41409      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
41410    }
41411
41412    if ($.type(settingContainer[settingName]) === 'number') {
41413      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
41414    } else {
41415      throw settingName + ' must be a number';
41416    }
41417  };
41418
41419  /**
41420   * Checks the sizeRangeSuffixes and, if necessary, converts
41421   * its keys from string (e.g. old settings with 'lt100') to int.
41422   */
41423  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
41424    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
41425      throw 'sizeRangeSuffixes must be defined and must be an object';
41426    }
41427
41428    var suffixRanges = [];
41429    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
41430      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
41431    }
41432
41433    var newSizeRngSuffixes = { 0: '' };
41434    for (var i = 0; i < suffixRanges.length; i++) {
41435      if ($.type(suffixRanges[i]) === 'string') {
41436        try {
41437          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
41438          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
41439        } catch (e) {
41440          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
41441        }
41442      } else {
41443        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
41444      }
41445    }
41446
41447    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
41448  };
41449
41450  /**
41451   * check and convert the maxRowHeight setting
41452   * requires rowHeight to be already set
41453   * TODO: should be always called when only rowHeight is changed
41454   * @return number or null
41455   */
41456  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
41457    var newMaxRowHeight = null;
41458    var rowHeight = this.settings.rowHeight;
41459
41460    if ($.type(this.settings.maxRowHeight) === 'string') {
41461      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
41462        newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
41463      } else {
41464        newMaxRowHeight = parseFloat(this.settings.maxRowHeight);
41465      }
41466    } else if ($.type(this.settings.maxRowHeight) === 'number') {
41467      newMaxRowHeight = this.settings.maxRowHeight;
41468    } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) {
41469      return null;
41470    } else {
41471      throw 'maxRowHeight must be a number or a percentage';
41472    }
41473
41474    // check if the converted value is not a number
41475    if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight';
41476
41477    // check values, maxRowHeight must be >= rowHeight
41478    if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight;
41479
41480    return newMaxRowHeight;
41481  };
41482
41483  /**
41484   * Checks the settings
41485   */
41486  JustifiedGallery.prototype.checkSettings = function () {
41487    this.checkSizeRangesSuffixes();
41488
41489    this.checkOrConvertNumber(this.settings, 'rowHeight');
41490    this.checkOrConvertNumber(this.settings, 'margins');
41491    this.checkOrConvertNumber(this.settings, 'border');
41492    this.checkOrConvertNumber(this.settings, 'maxRowsCount');
41493
41494    var lastRowModes = [
41495      'justify',
41496      'nojustify',
41497      'left',
41498      'center',
41499      'right',
41500      'hide'
41501    ];
41502    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
41503      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
41504    }
41505
41506    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
41507    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
41508      throw 'justifyThreshold must be in the interval [0,1]';
41509    }
41510    if ($.type(this.settings.cssAnimation) !== 'boolean') {
41511      throw 'cssAnimation must be a boolean';
41512    }
41513
41514    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
41515    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
41516
41517    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
41518    if (this.settings.captionSettings.visibleOpacity < 0 ||
41519      this.settings.captionSettings.visibleOpacity > 1) {
41520      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
41521    }
41522
41523    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
41524    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
41525      this.settings.captionSettings.nonVisibleOpacity > 1) {
41526      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
41527    }
41528
41529    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
41530    this.checkOrConvertNumber(this.settings, 'refreshTime');
41531    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
41532    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
41533    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
41534
41535    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
41536      throw 'sort must be false or a comparison function';
41537    }
41538
41539    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
41540      $.type(this.settings.filter) !== 'string') {
41541      throw 'filter must be false, a string or a filter function';
41542    }
41543  };
41544
41545  /**
41546   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
41547   * @returns {Array} sorted suffix ranges
41548   */
41549  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
41550    var suffixRanges = [];
41551    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
41552      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
41553    }
41554    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
41555    return suffixRanges;
41556  };
41557
41558  /**
41559   * Update the existing settings only changing some of them
41560   *
41561   * @param newSettings the new settings (or a subgroup of them)
41562   */
41563  JustifiedGallery.prototype.updateSettings = function (newSettings) {
41564    // In this case Justified Gallery has been called again changing only some options
41565    this.settings = $.extend({}, this.settings, newSettings);
41566    this.checkSettings();
41567
41568    // As reported in the settings: negative value = same as margins, 0 = disabled
41569    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
41570
41571    this.maxRowHeight = this.retrieveMaxRowHeight();
41572    this.suffixRanges = this.retrieveSuffixRanges();
41573  };
41574
41575  JustifiedGallery.prototype.defaults = {
41576    sizeRangeSuffixes: {}, /* e.g. Flickr configuration
41577        {
41578          100: '_t',  // used when longest is less than 100px
41579          240: '_m',  // used when longest is between 101px and 240px
41580          320: '_n',  // ...
41581          500: '',
41582          640: '_z',
41583          1024: '_b'  // used as else case because it is the last
41584        }
41585    */
41586    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
41587    path relative to a specific thumbnail size. The function should accept respectively three arguments:
41588    current path, width and height */
41589    rowHeight: 120, // required? required to be > 0?
41590    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
41591    // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
41592    // can't exceed 3 * rowHeight)
41593    maxRowsCount: 0, // maximum number of rows to be displayed (0 = disabled)
41594    margins: 1,
41595    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
41596
41597    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
41598
41599    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
41600                             * (i.e. lastRow setting is not considered) */
41601    waitThumbnailsLoad: true,
41602    captions: true,
41603    cssAnimation: true,
41604    imagesAnimationDuration: 500, // ignored with css animations
41605    captionSettings: { // ignored with css animations
41606      animationDuration: 500,
41607      visibleOpacity: 0.7,
41608      nonVisibleOpacity: 0.0
41609    },
41610    rel: null, // rewrite the rel of each analyzed links
41611    target: null, // rewrite the target of all links
41612    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
41613    refreshTime: 200, // time interval (in ms) to check if the page changes its width
41614    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
41615    randomize: false,
41616    rtl: false, // right-to-left mode
41617    sort: false, /*
41618      - false: to do not sort
41619      - function: to sort them using the function as comparator (see Array.prototype.sort())
41620    */
41621    filter: false, /*
41622      - false, null or undefined: for a disabled filter
41623      - a string: an entry is kept if entry.is(filter string) returns true
41624                  see jQuery's .is() function for further information
41625      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
41626                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
41627    */
41628    selector: 'a', // The selector that is used to know what are the entries of the gallery
41629    imgSelector: '> img, > a > img, > svg, > a > svg', // The selector that is used to know what are the images of each entry
41630    triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger
41631      this.$gallery.trigger(event);  // Consider that 'this' is this set to the JustifiedGallery object, so it can
41632    }                                // access to fields such as $gallery, useful to trigger events with jQuery.
41633  };
41634
41635
41636  /**
41637   * Justified Gallery plugin for jQuery
41638   *
41639   * Events
41640   *  - jg.complete : called when all the gallery has been created
41641   *  - jg.resize : called when the gallery has been resized
41642   *  - jg.rowflush : when a new row appears
41643   *
41644   * @param arg the action (or the settings) passed when the plugin is called
41645   * @returns {*} the object itself
41646   */
41647  $.fn.justifiedGallery = function (arg) {
41648    return this.each(function (index, gallery) {
41649
41650      var $gallery = $(gallery);
41651      $gallery.addClass('justified-gallery');
41652
41653      var controller = $gallery.data('jg.controller');
41654      if (typeof controller === 'undefined') {
41655        // Create controller and assign it to the object data
41656        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
41657          if (arg === 'destroy') return; // Just a call to an unexisting object
41658          throw 'The argument must be an object';
41659        }
41660        controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg));
41661        $gallery.data('jg.controller', controller);
41662      } else if (arg === 'norewind') {
41663        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
41664        // ... left to be more readable
41665      } else if (arg === 'destroy') {
41666        controller.destroy();
41667        return;
41668      } else {
41669        // In this case Justified Gallery has been called again changing only some options
41670        controller.updateSettings(arg);
41671        controller.rewind();
41672      }
41673
41674      // Update the entries list
41675      if (!controller.updateEntries(arg === 'norewind')) return;
41676
41677      // Init justified gallery
41678      controller.init();
41679
41680    });
41681  };
41682
41683}));
41684
41685/*!
41686* Customized version of iScroll.js 0.0.1
41687* It fixes bugs affecting its integration with fullpage.js
41688*/
41689/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
41690(function (window, document, Math) {
41691var rAF = window.requestAnimationFrame  ||
41692    window.webkitRequestAnimationFrame  ||
41693    window.mozRequestAnimationFrame     ||
41694    window.oRequestAnimationFrame       ||
41695    window.msRequestAnimationFrame      ||
41696    function (callback) { window.setTimeout(callback, 1000 / 60); };
41697
41698var utils = (function () {
41699    var me = {};
41700
41701    var _elementStyle = document.createElement('div').style;
41702    var _vendor = (function () {
41703        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
41704            transform,
41705            i = 0,
41706            l = vendors.length;
41707
41708        for ( ; i < l; i++ ) {
41709            transform = vendors[i] + 'ransform';
41710            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
41711        }
41712
41713        return false;
41714    })();
41715
41716    function _prefixStyle (style) {
41717        if ( _vendor === false ) return false;
41718        if ( _vendor === '' ) return style;
41719        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
41720    }
41721
41722    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
41723
41724    me.extend = function (target, obj) {
41725        for ( var i in obj ) {
41726            target[i] = obj[i];
41727        }
41728    };
41729
41730    me.addEvent = function (el, type, fn, capture) {
41731        el.addEventListener(type, fn, !!capture);
41732    };
41733
41734    me.removeEvent = function (el, type, fn, capture) {
41735        el.removeEventListener(type, fn, !!capture);
41736    };
41737
41738    me.prefixPointerEvent = function (pointerEvent) {
41739        return window.MSPointerEvent ?
41740            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
41741            pointerEvent;
41742    };
41743
41744    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
41745        var distance = current - start,
41746            speed = Math.abs(distance) / time,
41747            destination,
41748            duration;
41749
41750        deceleration = deceleration === undefined ? 0.0006 : deceleration;
41751
41752        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
41753        duration = speed / deceleration;
41754
41755        if ( destination < lowerMargin ) {
41756            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
41757            distance = Math.abs(destination - current);
41758            duration = distance / speed;
41759        } else if ( destination > 0 ) {
41760            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
41761            distance = Math.abs(current) + destination;
41762            duration = distance / speed;
41763        }
41764
41765        return {
41766            destination: Math.round(destination),
41767            duration: duration
41768        };
41769    };
41770
41771    var _transform = _prefixStyle('transform');
41772
41773    me.extend(me, {
41774        hasTransform: _transform !== false,
41775        hasPerspective: _prefixStyle('perspective') in _elementStyle,
41776        hasTouch: 'ontouchstart' in window,
41777        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
41778        hasTransition: _prefixStyle('transition') in _elementStyle
41779    });
41780
41781    /*
41782    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
41783    - galaxy S2 is ok
41784    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
41785    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
41786   - galaxy S3 is badAndroid (stock brower, webview)
41787     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
41788   - galaxy S4 is badAndroid (stock brower, webview)
41789     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
41790   - galaxy S5 is OK
41791     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
41792   - galaxy S6 is OK
41793     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
41794  */
41795    me.isBadAndroid = (function() {
41796        var appVersion = window.navigator.appVersion;
41797        // Android browser is not a chrome browser.
41798        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
41799            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
41800            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
41801                return parseFloat(safariVersion[1]) < 535.19;
41802            } else {
41803                return true;
41804            }
41805        } else {
41806            return false;
41807        }
41808    })();
41809
41810    me.extend(me.style = {}, {
41811        transform: _transform,
41812        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
41813        transitionDuration: _prefixStyle('transitionDuration'),
41814        transitionDelay: _prefixStyle('transitionDelay'),
41815        transformOrigin: _prefixStyle('transformOrigin')
41816    });
41817
41818    me.hasClass = function (e, c) {
41819        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
41820        return re.test(e.className);
41821    };
41822
41823    me.addClass = function (e, c) {
41824        if ( me.hasClass(e, c) ) {
41825            return;
41826        }
41827
41828        var newclass = e.className.split(' ');
41829        newclass.push(c);
41830        e.className = newclass.join(' ');
41831    };
41832
41833    me.removeClass = function (e, c) {
41834        if ( !me.hasClass(e, c) ) {
41835            return;
41836        }
41837
41838        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
41839        e.className = e.className.replace(re, ' ');
41840    };
41841
41842    me.offset = function (el) {
41843        var left = -el.offsetLeft,
41844            top = -el.offsetTop;
41845
41846        // jshint -W084
41847        while (el = el.offsetParent) {
41848            left -= el.offsetLeft;
41849            top -= el.offsetTop;
41850        }
41851        // jshint +W084
41852
41853        return {
41854            left: left,
41855            top: top
41856        };
41857    };
41858
41859    me.preventDefaultException = function (el, exceptions) {
41860        for ( var i in exceptions ) {
41861            if ( exceptions[i].test(el[i]) ) {
41862                return true;
41863            }
41864        }
41865
41866        return false;
41867    };
41868
41869    me.extend(me.eventType = {}, {
41870        touchstart: 1,
41871        touchmove: 1,
41872        touchend: 1,
41873
41874        mousedown: 2,
41875        mousemove: 2,
41876        mouseup: 2,
41877
41878        pointerdown: 3,
41879        pointermove: 3,
41880        pointerup: 3,
41881
41882        MSPointerDown: 3,
41883        MSPointerMove: 3,
41884        MSPointerUp: 3
41885    });
41886
41887    me.extend(me.ease = {}, {
41888        quadratic: {
41889            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
41890            fn: function (k) {
41891                return k * ( 2 - k );
41892            }
41893        },
41894        circular: {
41895            style: 'cubic-bezier(0.1, 0.57, 0.1, 1)',   // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
41896            fn: function (k) {
41897                return Math.sqrt( 1 - ( --k * k ) );
41898            }
41899        },
41900        back: {
41901            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
41902            fn: function (k) {
41903                var b = 4;
41904                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
41905            }
41906        },
41907        bounce: {
41908            style: '',
41909            fn: function (k) {
41910                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
41911                    return 7.5625 * k * k;
41912                } else if ( k < ( 2 / 2.75 ) ) {
41913                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
41914                } else if ( k < ( 2.5 / 2.75 ) ) {
41915                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
41916                } else {
41917                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
41918                }
41919            }
41920        },
41921        elastic: {
41922            style: '',
41923            fn: function (k) {
41924                var f = 0.22,
41925                    e = 0.4;
41926
41927                if ( k === 0 ) { return 0; }
41928                if ( k == 1 ) { return 1; }
41929
41930                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
41931            }
41932        }
41933    });
41934
41935    me.tap = function (e, eventName) {
41936        var ev = document.createEvent('Event');
41937        ev.initEvent(eventName, true, true);
41938        ev.pageX = e.pageX;
41939        ev.pageY = e.pageY;
41940        e.target.dispatchEvent(ev);
41941    };
41942
41943    me.click = function (e) {
41944        var target = e.target,
41945            ev;
41946
41947        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
41948            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
41949            // initMouseEvent is deprecated.
41950            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
41951            ev.initEvent('click', true, true);
41952            ev.view = e.view || window;
41953            ev.detail = 1;
41954            ev.screenX = target.screenX || 0;
41955            ev.screenY = target.screenY || 0;
41956            ev.clientX = target.clientX || 0;
41957            ev.clientY = target.clientY || 0;
41958            ev.ctrlKey = !!e.ctrlKey;
41959            ev.altKey = !!e.altKey;
41960            ev.shiftKey = !!e.shiftKey;
41961            ev.metaKey = !!e.metaKey;
41962            ev.button = 0;
41963            ev.relatedTarget = null;
41964            ev._constructed = true;
41965            target.dispatchEvent(ev);
41966        }
41967    };
41968
41969    return me;
41970})();
41971function IScroll (el, options) {
41972    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
41973    this.scroller = this.wrapper.children[0];
41974    this.scrollerStyle = this.scroller.style;       // cache style for better performance
41975
41976    this.options = {
41977
41978        resizeScrollbars: true,
41979
41980        mouseWheelSpeed: 20,
41981
41982        snapThreshold: 0.334,
41983
41984// INSERT POINT: OPTIONS
41985        disablePointer : !utils.hasPointer,
41986        disableTouch : utils.hasPointer || !utils.hasTouch,
41987        disableMouse : utils.hasPointer || utils.hasTouch,
41988        startX: 0,
41989        startY: 0,
41990        scrollY: true,
41991        directionLockThreshold: 5,
41992        momentum: true,
41993
41994        bounce: true,
41995        bounceTime: 600,
41996        bounceEasing: '',
41997
41998        preventDefault: true,
41999        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|LABEL)$/ },
42000
42001        HWCompositing: true,
42002        useTransition: true,
42003        useTransform: true,
42004        bindToWrapper: typeof window.onmousedown === "undefined"
42005    };
42006
42007    for ( var i in options ) {
42008        this.options[i] = options[i];
42009    }
42010
42011    // Normalize options
42012    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
42013
42014    this.options.useTransition = utils.hasTransition && this.options.useTransition;
42015    this.options.useTransform = utils.hasTransform && this.options.useTransform;
42016
42017    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
42018    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
42019
42020    // If you want eventPassthrough I have to lock one of the axes
42021    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
42022    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
42023
42024    // With eventPassthrough we also need lockDirection mechanism
42025    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
42026    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
42027
42028    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
42029
42030    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
42031
42032    if ( this.options.tap === true ) {
42033        this.options.tap = 'tap';
42034    }
42035
42036    // https://github.com/cubiq/iscroll/issues/1029
42037    if (!this.options.useTransition && !this.options.useTransform) {
42038        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
42039            this.scrollerStyle.position = "relative";
42040        }
42041    }
42042
42043    if ( this.options.shrinkScrollbars == 'scale' ) {
42044        this.options.useTransition = false;
42045    }
42046
42047    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
42048
42049// INSERT POINT: NORMALIZATION
42050
42051    // Some defaults
42052    this.x = 0;
42053    this.y = 0;
42054    this.directionX = 0;
42055    this.directionY = 0;
42056    this._events = {};
42057
42058// INSERT POINT: DEFAULTS
42059
42060    this._init();
42061    this.refresh();
42062
42063    this.scrollTo(this.options.startX, this.options.startY);
42064    this.enable();
42065}
42066
42067IScroll.prototype = {
42068    version: '5.2.0',
42069
42070    _init: function () {
42071        this._initEvents();
42072
42073        if ( this.options.scrollbars || this.options.indicators ) {
42074            this._initIndicators();
42075        }
42076
42077        if ( this.options.mouseWheel ) {
42078            this._initWheel();
42079        }
42080
42081        if ( this.options.snap ) {
42082            this._initSnap();
42083        }
42084
42085        if ( this.options.keyBindings ) {
42086            this._initKeys();
42087        }
42088
42089// INSERT POINT: _init
42090
42091    },
42092
42093    destroy: function () {
42094        this._initEvents(true);
42095        clearTimeout(this.resizeTimeout);
42096        this.resizeTimeout = null;
42097        this._execEvent('destroy');
42098    },
42099
42100    _transitionEnd: function (e) {
42101        if ( e.target != this.scroller || !this.isInTransition ) {
42102            return;
42103        }
42104
42105        this._transitionTime();
42106        if ( !this.resetPosition(this.options.bounceTime) ) {
42107            this.isInTransition = false;
42108            this._execEvent('scrollEnd');
42109        }
42110    },
42111
42112    _start: function (e) {
42113        // React to left mouse button only
42114        if ( utils.eventType[e.type] != 1 ) {
42115          // for button property
42116          // http://unixpapa.com/js/mouse.html
42117          var button;
42118        if (!e.which) {
42119          /* IE case */
42120          button = (e.button < 2) ? 0 :
42121                   ((e.button == 4) ? 1 : 2);
42122        } else {
42123          /* All others */
42124          button = e.button;
42125        }
42126            if ( button !== 0 ) {
42127                return;
42128            }
42129        }
42130
42131        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
42132            return;
42133        }
42134
42135        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
42136            e.preventDefault();
42137        }
42138
42139        var point = e.touches ? e.touches[0] : e,
42140            pos;
42141
42142        this.initiated  = utils.eventType[e.type];
42143        this.moved      = false;
42144        this.distX      = 0;
42145        this.distY      = 0;
42146        this.directionX = 0;
42147        this.directionY = 0;
42148        this.directionLocked = 0;
42149
42150        this.startTime = utils.getTime();
42151
42152        if ( this.options.useTransition && this.isInTransition ) {
42153            this._transitionTime();
42154            this.isInTransition = false;
42155            pos = this.getComputedPosition();
42156            this._translate(Math.round(pos.x), Math.round(pos.y));
42157            this._execEvent('scrollEnd');
42158        } else if ( !this.options.useTransition && this.isAnimating ) {
42159            this.isAnimating = false;
42160            this._execEvent('scrollEnd');
42161        }
42162
42163        this.startX    = this.x;
42164        this.startY    = this.y;
42165        this.absStartX = this.x;
42166        this.absStartY = this.y;
42167        this.pointX    = point.pageX;
42168        this.pointY    = point.pageY;
42169
42170        this._execEvent('beforeScrollStart');
42171    },
42172
42173    _move: function (e) {
42174        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
42175            return;
42176        }
42177
42178        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
42179            e.preventDefault();
42180        }
42181
42182        var point       = e.touches ? e.touches[0] : e,
42183            deltaX      = point.pageX - this.pointX,
42184            deltaY      = point.pageY - this.pointY,
42185            timestamp   = utils.getTime(),
42186            newX, newY,
42187            absDistX, absDistY;
42188
42189        this.pointX     = point.pageX;
42190        this.pointY     = point.pageY;
42191
42192        this.distX      += deltaX;
42193        this.distY      += deltaY;
42194        absDistX        = Math.abs(this.distX);
42195        absDistY        = Math.abs(this.distY);
42196
42197        // We need to move at least 10 pixels for the scrolling to initiate
42198        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
42199            return;
42200        }
42201
42202        // If you are scrolling in one direction lock the other
42203        if ( !this.directionLocked && !this.options.freeScroll ) {
42204            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
42205                this.directionLocked = 'h';     // lock horizontally
42206            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
42207                this.directionLocked = 'v';     // lock vertically
42208            } else {
42209                this.directionLocked = 'n';     // no lock
42210            }
42211        }
42212
42213        if ( this.directionLocked == 'h' ) {
42214            if ( this.options.eventPassthrough == 'vertical' ) {
42215                e.preventDefault();
42216            } else if ( this.options.eventPassthrough == 'horizontal' ) {
42217                this.initiated = false;
42218                return;
42219            }
42220
42221            deltaY = 0;
42222        } else if ( this.directionLocked == 'v' ) {
42223            if ( this.options.eventPassthrough == 'horizontal' ) {
42224                e.preventDefault();
42225            } else if ( this.options.eventPassthrough == 'vertical' ) {
42226                this.initiated = false;
42227                return;
42228            }
42229
42230            deltaX = 0;
42231        }
42232
42233        deltaX = this.hasHorizontalScroll ? deltaX : 0;
42234        deltaY = this.hasVerticalScroll ? deltaY : 0;
42235
42236        newX = this.x + deltaX;
42237        newY = this.y + deltaY;
42238
42239        // Slow down if outside of the boundaries
42240        if ( newX > 0 || newX < this.maxScrollX ) {
42241            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
42242        }
42243        if ( newY > 0 || newY < this.maxScrollY ) {
42244            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
42245        }
42246
42247        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
42248        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
42249
42250        if ( !this.moved ) {
42251            this._execEvent('scrollStart');
42252        }
42253
42254        this.moved = true;
42255
42256        this._translate(newX, newY);
42257
42258/* REPLACE START: _move */
42259
42260        if ( timestamp - this.startTime > 300 ) {
42261            this.startTime = timestamp;
42262            this.startX = this.x;
42263            this.startY = this.y;
42264        }
42265
42266/* REPLACE END: _move */
42267
42268    },
42269
42270    _end: function (e) {
42271        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
42272            return;
42273        }
42274
42275        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
42276            e.preventDefault();
42277        }
42278
42279        var point = e.changedTouches ? e.changedTouches[0] : e,
42280            momentumX,
42281            momentumY,
42282            duration = utils.getTime() - this.startTime,
42283            newX = Math.round(this.x),
42284            newY = Math.round(this.y),
42285            distanceX = Math.abs(newX - this.startX),
42286            distanceY = Math.abs(newY - this.startY),
42287            time = 0,
42288            easing = '';
42289
42290        this.isInTransition = 0;
42291        this.initiated = 0;
42292        this.endTime = utils.getTime();
42293
42294        // reset if we are outside of the boundaries
42295        if ( this.resetPosition(this.options.bounceTime) ) {
42296            return;
42297        }
42298
42299        this.scrollTo(newX, newY);  // ensures that the last position is rounded
42300
42301        // we scrolled less than 10 pixels
42302        if ( !this.moved ) {
42303            if ( this.options.tap ) {
42304                utils.tap(e, this.options.tap);
42305            }
42306
42307            if ( this.options.click ) {
42308                utils.click(e);
42309            }
42310
42311            this._execEvent('scrollCancel');
42312            return;
42313        }
42314
42315        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
42316            this._execEvent('flick');
42317            return;
42318        }
42319
42320        // start momentum animation if needed
42321        if ( this.options.momentum && duration < 300 ) {
42322            momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
42323            momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
42324            newX = momentumX.destination;
42325            newY = momentumY.destination;
42326            time = Math.max(momentumX.duration, momentumY.duration);
42327            this.isInTransition = 1;
42328        }
42329
42330
42331        if ( this.options.snap ) {
42332            var snap = this._nearestSnap(newX, newY);
42333            this.currentPage = snap;
42334            time = this.options.snapSpeed || Math.max(
42335                    Math.max(
42336                        Math.min(Math.abs(newX - snap.x), 1000),
42337                        Math.min(Math.abs(newY - snap.y), 1000)
42338                    ), 300);
42339            newX = snap.x;
42340            newY = snap.y;
42341
42342            this.directionX = 0;
42343            this.directionY = 0;
42344            easing = this.options.bounceEasing;
42345        }
42346
42347// INSERT POINT: _end
42348
42349        if ( newX != this.x || newY != this.y ) {
42350            // change easing function when scroller goes out of the boundaries
42351            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
42352                easing = utils.ease.quadratic;
42353            }
42354
42355            this.scrollTo(newX, newY, time, easing);
42356            return;
42357        }
42358
42359        this._execEvent('scrollEnd');
42360    },
42361
42362    _resize: function () {
42363        var that = this;
42364
42365        clearTimeout(this.resizeTimeout);
42366
42367        this.resizeTimeout = setTimeout(function () {
42368            that.refresh();
42369        }, this.options.resizePolling);
42370    },
42371
42372    resetPosition: function (time) {
42373        var x = this.x,
42374            y = this.y;
42375
42376        time = time || 0;
42377
42378        if ( !this.hasHorizontalScroll || this.x > 0 ) {
42379            x = 0;
42380        } else if ( this.x < this.maxScrollX ) {
42381            x = this.maxScrollX;
42382        }
42383
42384        if ( !this.hasVerticalScroll || this.y > 0 ) {
42385            y = 0;
42386        } else if ( this.y < this.maxScrollY ) {
42387            y = this.maxScrollY;
42388        }
42389
42390        if ( x == this.x && y == this.y ) {
42391            return false;
42392        }
42393
42394        this.scrollTo(x, y, time, this.options.bounceEasing);
42395
42396        return true;
42397    },
42398
42399    disable: function () {
42400        this.enabled = false;
42401    },
42402
42403    enable: function () {
42404        this.enabled = true;
42405    },
42406
42407    refresh: function () {
42408        var rf = this.wrapper.offsetHeight;     // Force reflow
42409
42410        this.wrapperWidth   = this.wrapper.clientWidth;
42411        this.wrapperHeight  = this.wrapper.clientHeight;
42412
42413/* REPLACE START: refresh */
42414
42415        this.scrollerWidth  = this.scroller.offsetWidth;
42416        this.scrollerHeight = this.scroller.offsetHeight;
42417
42418        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
42419        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
42420
42421/* REPLACE END: refresh */
42422
42423        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
42424        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
42425
42426        if ( !this.hasHorizontalScroll ) {
42427            this.maxScrollX = 0;
42428            this.scrollerWidth = this.wrapperWidth;
42429        }
42430
42431        if ( !this.hasVerticalScroll ) {
42432            this.maxScrollY = 0;
42433            this.scrollerHeight = this.wrapperHeight;
42434        }
42435
42436        this.endTime = 0;
42437        this.directionX = 0;
42438        this.directionY = 0;
42439
42440        this.wrapperOffset = utils.offset(this.wrapper);
42441
42442        this._execEvent('refresh');
42443
42444        this.resetPosition();
42445
42446// INSERT POINT: _refresh
42447
42448    },
42449
42450
42451    on: function (type, fn) {
42452        if ( !this._events[type] ) {
42453            this._events[type] = [];
42454        }
42455
42456        this._events[type].push(fn);
42457    },
42458
42459    off: function (type, fn) {
42460        if ( !this._events[type] ) {
42461            return;
42462        }
42463
42464        var index = this._events[type].indexOf(fn);
42465
42466        if ( index > -1 ) {
42467            this._events[type].splice(index, 1);
42468        }
42469    },
42470
42471    _execEvent: function (type) {
42472        if ( !this._events[type] ) {
42473            return;
42474        }
42475
42476        var i = 0,
42477            l = this._events[type].length;
42478
42479        if ( !l ) {
42480            return;
42481        }
42482
42483        for ( ; i < l; i++ ) {
42484            this._events[type][i].apply(this, [].slice.call(arguments, 1));
42485        }
42486    },
42487
42488    scrollBy: function (x, y, time, easing) {
42489        x = this.x + x;
42490        y = this.y + y;
42491        time = time || 0;
42492
42493        this.scrollTo(x, y, time, easing);
42494    },
42495
42496    scrollTo: function (x, y, time, easing) {
42497        easing = easing || utils.ease.circular;
42498
42499        this.isInTransition = this.options.useTransition && time > 0;
42500        var transitionType = this.options.useTransition && easing.style;
42501        if ( !time || transitionType ) {
42502                if(transitionType) {
42503                    this._transitionTimingFunction(easing.style);
42504                    this._transitionTime(time);
42505                }
42506            this._translate(x, y);
42507        } else {
42508            this._animate(x, y, time, easing.fn);
42509        }
42510    },
42511
42512    scrollToElement: function (el, time, offsetX, offsetY, easing) {
42513        el = el.nodeType ? el : this.scroller.querySelector(el);
42514
42515        if ( !el ) {
42516            return;
42517        }
42518
42519        var pos = utils.offset(el);
42520
42521        pos.left -= this.wrapperOffset.left;
42522        pos.top  -= this.wrapperOffset.top;
42523
42524        // if offsetX/Y are true we center the element to the screen
42525        if ( offsetX === true ) {
42526            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
42527        }
42528        if ( offsetY === true ) {
42529            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
42530        }
42531
42532        pos.left -= offsetX || 0;
42533        pos.top  -= offsetY || 0;
42534
42535        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
42536        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
42537
42538        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
42539
42540        this.scrollTo(pos.left, pos.top, time, easing);
42541    },
42542
42543    _transitionTime: function (time) {
42544        if (!this.options.useTransition) {
42545            return;
42546        }
42547        time = time || 0;
42548        var durationProp = utils.style.transitionDuration;
42549        if(!durationProp) {
42550            return;
42551        }
42552
42553        this.scrollerStyle[durationProp] = time + 'ms';
42554
42555        if ( !time && utils.isBadAndroid ) {
42556            this.scrollerStyle[durationProp] = '0.0001ms';
42557            // remove 0.0001ms
42558            var self = this;
42559            rAF(function() {
42560                if(self.scrollerStyle[durationProp] === '0.0001ms') {
42561                    self.scrollerStyle[durationProp] = '0s';
42562                }
42563            });
42564        }
42565
42566
42567        if ( this.indicators ) {
42568            for ( var i = this.indicators.length; i--; ) {
42569                this.indicators[i].transitionTime(time);
42570            }
42571        }
42572
42573
42574// INSERT POINT: _transitionTime
42575
42576    },
42577
42578    _transitionTimingFunction: function (easing) {
42579        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
42580
42581
42582        if ( this.indicators ) {
42583            for ( var i = this.indicators.length; i--; ) {
42584                this.indicators[i].transitionTimingFunction(easing);
42585            }
42586        }
42587
42588
42589// INSERT POINT: _transitionTimingFunction
42590
42591    },
42592
42593    _translate: function (x, y) {
42594        //Uncode addition
42595        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
42596            return false;
42597
42598        if ( this.options.useTransform ) {
42599
42600/* REPLACE START: _translate */
42601
42602            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
42603
42604/* REPLACE END: _translate */
42605
42606        } else {
42607            x = Math.round(x);
42608            y = Math.round(y);
42609            this.scrollerStyle.left = x + 'px';
42610            this.scrollerStyle.top = y + 'px';
42611        }
42612
42613        this.x = x;
42614        this.y = y;
42615
42616
42617        if ( this.indicators ) {
42618            for ( var i = this.indicators.length; i--; ) {
42619                this.indicators[i].updatePosition();
42620            }
42621        }
42622
42623        //Uncode addition
42624        var uncodevent = new CustomEvent('fp-slide-scroll');
42625        window.dispatchEvent(uncodevent);
42626
42627// INSERT POINT: _translate
42628
42629    },
42630
42631    _initEvents: function (remove) {
42632        var eventType = remove ? utils.removeEvent : utils.addEvent,
42633            target = this.options.bindToWrapper ? this.wrapper : window;
42634
42635        eventType(window, 'orientationchange', this);
42636        eventType(window, 'resize', this);
42637
42638        if ( this.options.click ) {
42639            eventType(this.wrapper, 'click', this, true);
42640        }
42641
42642        if ( !this.options.disableMouse ) {
42643            eventType(this.wrapper, 'mousedown', this);
42644            eventType(target, 'mousemove', this);
42645            eventType(target, 'mousecancel', this);
42646            eventType(target, 'mouseup', this);
42647        }
42648
42649        if ( utils.hasPointer && !this.options.disablePointer ) {
42650            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
42651            eventType(target, utils.prefixPointerEvent('pointermove'), this);
42652            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
42653            eventType(target, utils.prefixPointerEvent('pointerup'), this);
42654        }
42655
42656        if ( utils.hasTouch && !this.options.disableTouch ) {
42657            eventType(this.wrapper, 'touchstart', this);
42658            eventType(target, 'touchmove', this);
42659            eventType(target, 'touchcancel', this);
42660            eventType(target, 'touchend', this);
42661        }
42662
42663        eventType(this.scroller, 'transitionend', this);
42664        eventType(this.scroller, 'webkitTransitionEnd', this);
42665        eventType(this.scroller, 'oTransitionEnd', this);
42666        eventType(this.scroller, 'MSTransitionEnd', this);
42667    },
42668
42669    getComputedPosition: function () {
42670        var matrix = window.getComputedStyle(this.scroller, null),
42671            x, y;
42672
42673        if ( this.options.useTransform ) {
42674            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
42675            x = +(matrix[12] || matrix[4]);
42676            y = +(matrix[13] || matrix[5]);
42677        } else {
42678            x = +matrix.left.replace(/[^-\d.]/g, '');
42679            y = +matrix.top.replace(/[^-\d.]/g, '');
42680        }
42681
42682        return { x: x, y: y };
42683    },
42684    _initIndicators: function () {
42685        var interactive = this.options.interactiveScrollbars,
42686            customStyle = typeof this.options.scrollbars != 'string',
42687            indicators = [],
42688            indicator;
42689
42690        var that = this;
42691
42692        this.indicators = [];
42693
42694        if ( this.options.scrollbars ) {
42695            // Vertical scrollbar
42696            if ( this.options.scrollY ) {
42697                indicator = {
42698                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
42699                    interactive: interactive,
42700                    defaultScrollbars: true,
42701                    customStyle: customStyle,
42702                    resize: this.options.resizeScrollbars,
42703                    shrink: this.options.shrinkScrollbars,
42704                    fade: this.options.fadeScrollbars,
42705                    listenX: false
42706                };
42707
42708                this.wrapper.appendChild(indicator.el);
42709                indicators.push(indicator);
42710            }
42711
42712            // Horizontal scrollbar
42713            if ( this.options.scrollX ) {
42714                indicator = {
42715                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
42716                    interactive: interactive,
42717                    defaultScrollbars: true,
42718                    customStyle: customStyle,
42719                    resize: this.options.resizeScrollbars,
42720                    shrink: this.options.shrinkScrollbars,
42721                    fade: this.options.fadeScrollbars,
42722                    listenY: false
42723                };
42724
42725                this.wrapper.appendChild(indicator.el);
42726                indicators.push(indicator);
42727            }
42728        }
42729
42730        if ( this.options.indicators ) {
42731            // TODO: check concat compatibility
42732            indicators = indicators.concat(this.options.indicators);
42733        }
42734
42735        for ( var i = indicators.length; i--; ) {
42736            this.indicators.push( new Indicator(this, indicators[i]) );
42737        }
42738
42739        // TODO: check if we can use array.map (wide compatibility and performance issues)
42740        function _indicatorsMap (fn) {
42741            if (that.indicators) {
42742                for ( var i = that.indicators.length; i--; ) {
42743                    fn.call(that.indicators[i]);
42744                }
42745            }
42746        }
42747
42748        if ( this.options.fadeScrollbars ) {
42749            this.on('scrollEnd', function () {
42750                _indicatorsMap(function () {
42751                    this.fade();
42752                });
42753            });
42754
42755            this.on('scrollCancel', function () {
42756                _indicatorsMap(function () {
42757                    this.fade();
42758                });
42759            });
42760
42761            this.on('scrollStart', function () {
42762                _indicatorsMap(function () {
42763                    this.fade(1);
42764                });
42765            });
42766
42767            this.on('beforeScrollStart', function () {
42768                _indicatorsMap(function () {
42769                    this.fade(1, true);
42770                });
42771            });
42772        }
42773
42774
42775        this.on('refresh', function () {
42776            _indicatorsMap(function () {
42777                this.refresh();
42778            });
42779        });
42780
42781        this.on('destroy', function () {
42782            _indicatorsMap(function () {
42783                this.destroy();
42784            });
42785
42786            delete this.indicators;
42787        });
42788    },
42789
42790    _initWheel: function () {
42791        utils.addEvent(this.wrapper, 'wheel', this);
42792        utils.addEvent(this.wrapper, 'mousewheel', this);
42793        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
42794
42795        this.on('destroy', function () {
42796            clearTimeout(this.wheelTimeout);
42797            this.wheelTimeout = null;
42798            utils.removeEvent(this.wrapper, 'wheel', this);
42799            utils.removeEvent(this.wrapper, 'mousewheel', this);
42800            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
42801        });
42802    },
42803
42804    _wheel: function (e) {
42805        if ( !this.enabled ) {
42806            return;
42807        }
42808
42809        var wheelDeltaX, wheelDeltaY,
42810            newX, newY,
42811            that = this;
42812
42813        if ( this.wheelTimeout === undefined ) {
42814            that._execEvent('scrollStart');
42815        }
42816
42817        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
42818        clearTimeout(this.wheelTimeout);
42819        this.wheelTimeout = setTimeout(function () {
42820            if(!that.options.snap) {
42821                that._execEvent('scrollEnd');
42822            }
42823            that.wheelTimeout = undefined;
42824        }, 400);
42825
42826        if ( 'deltaX' in e ) {
42827            if (e.deltaMode === 1) {
42828                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
42829                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
42830            } else {
42831                wheelDeltaX = -e.deltaX;
42832                wheelDeltaY = -e.deltaY;
42833            }
42834        } else if ( 'wheelDeltaX' in e ) {
42835            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
42836            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
42837        } else if ( 'wheelDelta' in e ) {
42838            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
42839        } else if ( 'detail' in e ) {
42840            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
42841        } else {
42842            return;
42843        }
42844
42845        wheelDeltaX *= this.options.invertWheelDirection;
42846        wheelDeltaY *= this.options.invertWheelDirection;
42847
42848        if ( !this.hasVerticalScroll ) {
42849            wheelDeltaX = wheelDeltaY;
42850            wheelDeltaY = 0;
42851        }
42852
42853        if ( this.options.snap ) {
42854            newX = this.currentPage.pageX;
42855            newY = this.currentPage.pageY;
42856
42857            if ( wheelDeltaX > 0 ) {
42858                newX--;
42859            } else if ( wheelDeltaX < 0 ) {
42860                newX++;
42861            }
42862
42863            if ( wheelDeltaY > 0 ) {
42864                newY--;
42865            } else if ( wheelDeltaY < 0 ) {
42866                newY++;
42867            }
42868
42869            this.goToPage(newX, newY);
42870
42871            return;
42872        }
42873
42874        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
42875        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
42876
42877        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
42878        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
42879
42880        if ( newX > 0 ) {
42881            newX = 0;
42882        } else if ( newX < this.maxScrollX ) {
42883            newX = this.maxScrollX;
42884        }
42885
42886        if ( newY > 0 ) {
42887            newY = 0;
42888        } else if ( newY < this.maxScrollY ) {
42889            newY = this.maxScrollY;
42890        }
42891
42892        this.scrollTo(newX, newY, 0);
42893
42894// INSERT POINT: _wheel
42895    },
42896
42897    _initSnap: function () {
42898        this.currentPage = {};
42899
42900        if ( typeof this.options.snap == 'string' ) {
42901            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
42902        }
42903
42904        this.on('refresh', function () {
42905            var i = 0, l,
42906                m = 0, n,
42907                cx, cy,
42908                x = 0, y,
42909                stepX = this.options.snapStepX || this.wrapperWidth,
42910                stepY = this.options.snapStepY || this.wrapperHeight,
42911                el;
42912
42913            this.pages = [];
42914
42915            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
42916                return;
42917            }
42918
42919            if ( this.options.snap === true ) {
42920                cx = Math.round( stepX / 2 );
42921                cy = Math.round( stepY / 2 );
42922
42923                while ( x > -this.scrollerWidth ) {
42924                    this.pages[i] = [];
42925                    l = 0;
42926                    y = 0;
42927
42928                    while ( y > -this.scrollerHeight ) {
42929                        this.pages[i][l] = {
42930                            x: Math.max(x, this.maxScrollX),
42931                            y: Math.max(y, this.maxScrollY),
42932                            width: stepX,
42933                            height: stepY,
42934                            cx: x - cx,
42935                            cy: y - cy
42936                        };
42937
42938                        y -= stepY;
42939                        l++;
42940                    }
42941
42942                    x -= stepX;
42943                    i++;
42944                }
42945            } else {
42946                el = this.options.snap;
42947                l = el.length;
42948                n = -1;
42949
42950                for ( ; i < l; i++ ) {
42951                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
42952                        m = 0;
42953                        n++;
42954                    }
42955
42956                    if ( !this.pages[m] ) {
42957                        this.pages[m] = [];
42958                    }
42959
42960                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
42961                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
42962                    cx = x - Math.round(el[i].offsetWidth / 2);
42963                    cy = y - Math.round(el[i].offsetHeight / 2);
42964
42965                    this.pages[m][n] = {
42966                        x: x,
42967                        y: y,
42968                        width: el[i].offsetWidth,
42969                        height: el[i].offsetHeight,
42970                        cx: cx,
42971                        cy: cy
42972                    };
42973
42974                    if ( x > this.maxScrollX ) {
42975                        m++;
42976                    }
42977                }
42978            }
42979
42980            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
42981
42982            // Update snap threshold if needed
42983            if ( this.options.snapThreshold % 1 === 0 ) {
42984                this.snapThresholdX = this.options.snapThreshold;
42985                this.snapThresholdY = this.options.snapThreshold;
42986            } else {
42987                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
42988                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
42989            }
42990        });
42991
42992        this.on('flick', function () {
42993            var time = this.options.snapSpeed || Math.max(
42994                    Math.max(
42995                        Math.min(Math.abs(this.x - this.startX), 1000),
42996                        Math.min(Math.abs(this.y - this.startY), 1000)
42997                    ), 300);
42998
42999            this.goToPage(
43000                this.currentPage.pageX + this.directionX,
43001                this.currentPage.pageY + this.directionY,
43002                time
43003            );
43004        });
43005    },
43006
43007    _nearestSnap: function (x, y) {
43008        if ( !this.pages.length ) {
43009            return { x: 0, y: 0, pageX: 0, pageY: 0 };
43010        }
43011
43012        var i = 0,
43013            l = this.pages.length,
43014            m = 0;
43015
43016        // Check if we exceeded the snap threshold
43017        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
43018            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
43019            return this.currentPage;
43020        }
43021
43022        if ( x > 0 ) {
43023            x = 0;
43024        } else if ( x < this.maxScrollX ) {
43025            x = this.maxScrollX;
43026        }
43027
43028        if ( y > 0 ) {
43029            y = 0;
43030        } else if ( y < this.maxScrollY ) {
43031            y = this.maxScrollY;
43032        }
43033
43034        for ( ; i < l; i++ ) {
43035            if ( x >= this.pages[i][0].cx ) {
43036                x = this.pages[i][0].x;
43037                break;
43038            }
43039        }
43040
43041        l = this.pages[i].length;
43042
43043        for ( ; m < l; m++ ) {
43044            if ( y >= this.pages[0][m].cy ) {
43045                y = this.pages[0][m].y;
43046                break;
43047            }
43048        }
43049
43050        if ( i == this.currentPage.pageX ) {
43051            i += this.directionX;
43052
43053            if ( i < 0 ) {
43054                i = 0;
43055            } else if ( i >= this.pages.length ) {
43056                i = this.pages.length - 1;
43057            }
43058
43059            x = this.pages[i][0].x;
43060        }
43061
43062        if ( m == this.currentPage.pageY ) {
43063            m += this.directionY;
43064
43065            if ( m < 0 ) {
43066                m = 0;
43067            } else if ( m >= this.pages[0].length ) {
43068                m = this.pages[0].length - 1;
43069            }
43070
43071            y = this.pages[0][m].y;
43072        }
43073
43074        return {
43075            x: x,
43076            y: y,
43077            pageX: i,
43078            pageY: m
43079        };
43080    },
43081
43082    goToPage: function (x, y, time, easing) {
43083        easing = easing || this.options.bounceEasing;
43084
43085        if ( x >= this.pages.length ) {
43086            x = this.pages.length - 1;
43087        } else if ( x < 0 ) {
43088            x = 0;
43089        }
43090
43091        if ( y >= this.pages[x].length ) {
43092            y = this.pages[x].length - 1;
43093        } else if ( y < 0 ) {
43094            y = 0;
43095        }
43096
43097        var posX = this.pages[x][y].x,
43098            posY = this.pages[x][y].y;
43099
43100        time = time === undefined ? this.options.snapSpeed || Math.max(
43101            Math.max(
43102                Math.min(Math.abs(posX - this.x), 1000),
43103                Math.min(Math.abs(posY - this.y), 1000)
43104            ), 300) : time;
43105
43106        this.currentPage = {
43107            x: posX,
43108            y: posY,
43109            pageX: x,
43110            pageY: y
43111        };
43112
43113        this.scrollTo(posX, posY, time, easing);
43114    },
43115
43116    next: function (time, easing) {
43117        var x = this.currentPage.pageX,
43118            y = this.currentPage.pageY;
43119
43120        x++;
43121
43122        if ( x >= this.pages.length && this.hasVerticalScroll ) {
43123            x = 0;
43124            y++;
43125        }
43126
43127        this.goToPage(x, y, time, easing);
43128    },
43129
43130    prev: function (time, easing) {
43131        var x = this.currentPage.pageX,
43132            y = this.currentPage.pageY;
43133
43134        x--;
43135
43136        if ( x < 0 && this.hasVerticalScroll ) {
43137            x = 0;
43138            y--;
43139        }
43140
43141        this.goToPage(x, y, time, easing);
43142    },
43143
43144    _initKeys: function (e) {
43145        // default key bindings
43146        var keys = {
43147            pageUp: 33,
43148            pageDown: 34,
43149            end: 35,
43150            home: 36,
43151            left: 37,
43152            up: 38,
43153            right: 39,
43154            down: 40
43155        };
43156        var i;
43157
43158        // if you give me characters I give you keycode
43159        if ( typeof this.options.keyBindings == 'object' ) {
43160            for ( i in this.options.keyBindings ) {
43161                if ( typeof this.options.keyBindings[i] == 'string' ) {
43162                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
43162deAt(0);
43163                }
43164            }
43165        } else {
43166            this.options.keyBindings = {};
43167        }
43168
43169        for ( i in keys ) {
43170            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
43171        }
43172
43173        utils.addEvent(window, 'keydown', this);
43174
43175        this.on('destroy', function () {
43176            utils.removeEvent(window, 'keydown', this);
43177        });
43178    },
43179
43180    _key: function (e) {
43181        if ( !this.enabled ) {
43182            return;
43183        }
43184
43185        var snap = this.options.snap,   // we are using this alot, better to cache it
43186            newX = snap ? this.currentPage.pageX : this.x,
43187            newY = snap ? this.currentPage.pageY : this.y,
43188            now = utils.getTime(),
43189            prevTime = this.keyTime || 0,
43190            acceleration = 0.250,
43191            pos;
43192
43193        if ( this.options.useTransition && this.isInTransition ) {
43194            pos = this.getComputedPosition();
43195
43196            this._translate(Math.round(pos.x), Math.round(pos.y));
43197            this.isInTransition = false;
43198        }
43199
43200        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
43201
43202        switch ( e.keyCode ) {
43203            case this.options.keyBindings.pageUp:
43204                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
43205                    newX += snap ? 1 : this.wrapperWidth;
43206                } else {
43207                    newY += snap ? 1 : this.wrapperHeight;
43208                }
43209                break;
43210            case this.options.keyBindings.pageDown:
43211                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
43212                    newX -= snap ? 1 : this.wrapperWidth;
43213                } else {
43214                    newY -= snap ? 1 : this.wrapperHeight;
43215                }
43216                break;
43217            case this.options.keyBindings.end:
43218                newX = snap ? this.pages.length-1 : this.maxScrollX;
43219                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
43220                break;
43221            case this.options.keyBindings.home:
43222                newX = 0;
43223                newY = 0;
43224                break;
43225            case this.options.keyBindings.left:
43226                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
43227                break;
43228            case this.options.keyBindings.up:
43229                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
43230                break;
43231            case this.options.keyBindings.right:
43232                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
43233                break;
43234            case this.options.keyBindings.down:
43235                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
43236                break;
43237            default:
43238                return;
43239        }
43240
43241        if ( snap ) {
43242            this.goToPage(newX, newY);
43243            return;
43244        }
43245
43246        if ( newX > 0 ) {
43247            newX = 0;
43248            this.keyAcceleration = 0;
43249        } else if ( newX < this.maxScrollX ) {
43250            newX = this.maxScrollX;
43251            this.keyAcceleration = 0;
43252        }
43253
43254        if ( newY > 0 ) {
43255            newY = 0;
43256            this.keyAcceleration = 0;
43257        } else if ( newY < this.maxScrollY ) {
43258            newY = this.maxScrollY;
43259            this.keyAcceleration = 0;
43260        }
43261
43262        this.scrollTo(newX, newY, 0);
43263
43264        this.keyTime = now;
43265    },
43266
43267    _animate: function (destX, destY, duration, easingFn) {
43268        var that = this,
43269            startX = this.x,
43270            startY = this.y,
43271            startTime = utils.getTime(),
43272            destTime = startTime + duration;
43273
43274        function step () {
43275            var now = utils.getTime(),
43276                newX, newY,
43277                easing;
43278
43279            if ( now >= destTime ) {
43280                that.isAnimating = false;
43281                that._translate(destX, destY);
43282
43283                if ( !that.resetPosition(that.options.bounceTime) ) {
43284                    that._execEvent('scrollEnd');
43285                }
43286
43287                return;
43288            }
43289
43290            now = ( now - startTime ) / duration;
43291            easing = easingFn(now);
43292            newX = ( destX - startX ) * easing + startX;
43293            newY = ( destY - startY ) * easing + startY;
43294            that._translate(newX, newY);
43295
43296            if ( that.isAnimating ) {
43297                rAF(step);
43298            }
43299        }
43300
43301        this.isAnimating = true;
43302        step();
43303    },
43304    handleEvent: function (e) {
43305        switch ( e.type ) {
43306            case 'touchstart':
43307            case 'pointerdown':
43308            case 'MSPointerDown':
43309            case 'mousedown':
43310                this._start(e);
43311                break;
43312            case 'touchmove':
43313            case 'pointermove':
43314            case 'MSPointerMove':
43315            case 'mousemove':
43316                this._move(e);
43317                break;
43318            case 'touchend':
43319            case 'pointerup':
43320            case 'MSPointerUp':
43321            case 'mouseup':
43322            case 'touchcancel':
43323            case 'pointercancel':
43324            case 'MSPointerCancel':
43325            case 'mousecancel':
43326                this._end(e);
43327                break;
43328            case 'orientationchange':
43329            case 'resize':
43330                this._resize();
43331                break;
43332            case 'transitionend':
43333            case 'webkitTransitionEnd':
43334            case 'oTransitionEnd':
43335            case 'MSTransitionEnd':
43336                this._transitionEnd(e);
43337                break;
43338            case 'wheel':
43339            case 'DOMMouseScroll':
43340            case 'mousewheel':
43341                this._wheel(e);
43342                break;
43343            case 'keydown':
43344                this._key(e);
43345                break;
43346            case 'click':
43347                if ( this.enabled && !e._constructed ) {
43348                    e.preventDefault();
43349                    e.stopPropagation();
43350                }
43351                break;
43352        }
43353    }
43354};
43355function createDefaultScrollbar (direction, interactive, type) {
43356    var scrollbar = document.createElement('div'),
43357        indicator = document.createElement('div');
43358
43359    if ( type === true ) {
43360        scrollbar.style.cssText = 'position:absolute;z-index:9999';
43361        indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
43362    }
43363
43364    indicator.className = 'iScrollIndicator';
43365
43366    if ( direction == 'h' ) {
43367        if ( type === true ) {
43368            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
43369            indicator.style.height = '100%';
43370        }
43371        scrollbar.className = 'iScrollHorizontalScrollbar';
43372    } else {
43373        if ( type === true ) {
43374            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
43375            indicator.style.width = '100%';
43376        }
43377        scrollbar.className = 'iScrollVerticalScrollbar';
43378    }
43379
43380    scrollbar.style.cssText += ';overflow:hidden';
43381
43382    if ( !interactive ) {
43383        scrollbar.style.pointerEvents = 'none';
43384    }
43385
43386    scrollbar.appendChild(indicator);
43387
43388    return scrollbar;
43389}
43390
43391function Indicator (scroller, options) {
43392    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
43393    this.wrapperStyle = this.wrapper.style;
43394    this.indicator = this.wrapper.children[0];
43395    this.indicatorStyle = this.indicator.style;
43396    this.scroller = scroller;
43397
43398    this.options = {
43399        listenX: true,
43400        listenY: true,
43401        interactive: false,
43402        resize: true,
43403        defaultScrollbars: false,
43404        shrink: false,
43405        fade: false,
43406        speedRatioX: 0,
43407        speedRatioY: 0
43408    };
43409
43410    for ( var i in options ) {
43411        this.options[i] = options[i];
43412    }
43413
43414    this.sizeRatioX = 1;
43415    this.sizeRatioY = 1;
43416    this.maxPosX = 0;
43417    this.maxPosY = 0;
43418
43419    if ( this.options.interactive ) {
43420        if ( !this.options.disableTouch ) {
43421            utils.addEvent(this.indicator, 'touchstart', this);
43422            utils.addEvent(window, 'touchend', this);
43423        }
43424        if ( !this.options.disablePointer ) {
43425            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
43426            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
43427        }
43428        if ( !this.options.disableMouse ) {
43429            utils.addEvent(this.indicator, 'mousedown', this);
43430            utils.addEvent(window, 'mouseup', this);
43431        }
43432    }
43433
43434    if ( this.options.fade ) {
43435        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
43436        var durationProp = utils.style.transitionDuration;
43437        if(!durationProp) {
43438            return;
43439        }
43440        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
43441        // remove 0.0001ms
43442        var self = this;
43443        if(utils.isBadAndroid) {
43444            rAF(function() {
43445                if(self.wrapperStyle[durationProp] === '0.0001ms') {
43446                    self.wrapperStyle[durationProp] = '0s';
43447                }
43448            });
43449        }
43450        this.wrapperStyle.opacity = '0';
43451    }
43452}
43453
43454Indicator.prototype = {
43455    handleEvent: function (e) {
43456        switch ( e.type ) {
43457            case 'touchstart':
43458            case 'pointerdown':
43459            case 'MSPointerDown':
43460            case 'mousedown':
43461                this._start(e);
43462                break;
43463            case 'touchmove':
43464            case 'pointermove':
43465            case 'MSPointerMove':
43466            case 'mousemove':
43467                this._move(e);
43468                break;
43469            case 'touchend':
43470            case 'pointerup':
43471            case 'MSPointerUp':
43472            case 'mouseup':
43473            case 'touchcancel':
43474            case 'pointercancel':
43475            case 'MSPointerCancel':
43476            case 'mousecancel':
43477                this._end(e);
43478                break;
43479        }
43480    },
43481
43482    destroy: function () {
43483        if ( this.options.fadeScrollbars ) {
43484            clearTimeout(this.fadeTimeout);
43485            this.fadeTimeout = null;
43486        }
43487        if ( this.options.interactive ) {
43488            utils.removeEvent(this.indicator, 'touchstart', this);
43489            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
43490            utils.removeEvent(this.indicator, 'mousedown', this);
43491
43492            utils.removeEvent(window, 'touchmove', this);
43493            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
43494            utils.removeEvent(window, 'mousemove', this);
43495
43496            utils.removeEvent(window, 'touchend', this);
43497            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
43498            utils.removeEvent(window, 'mouseup', this);
43499        }
43500
43501        if ( this.options.defaultScrollbars ) {
43502            this.wrapper.parentNode.removeChild(this.wrapper);
43503        }
43504    },
43505
43506    _start: function (e) {
43507        var point = e.touches ? e.touches[0] : e;
43508
43509        e.preventDefault();
43510        e.stopPropagation();
43511
43512        this.transitionTime();
43513
43514        this.initiated = true;
43515        this.moved = false;
43516        this.lastPointX = point.pageX;
43517        this.lastPointY = point.pageY;
43518
43519        this.startTime  = utils.getTime();
43520
43521        if ( !this.options.disableTouch ) {
43522            utils.addEvent(window, 'touchmove', this);
43523        }
43524        if ( !this.options.disablePointer ) {
43525            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
43526        }
43527        if ( !this.options.disableMouse ) {
43528            utils.addEvent(window, 'mousemove', this);
43529        }
43530
43531        this.scroller._execEvent('beforeScrollStart');
43532    },
43533
43534    _move: function (e) {
43535        var point = e.touches ? e.touches[0] : e,
43536            deltaX, deltaY,
43537            newX, newY,
43538            timestamp = utils.getTime();
43539
43540        if ( !this.moved ) {
43541            this.scroller._execEvent('scrollStart');
43542        }
43543
43544        this.moved = true;
43545
43546        deltaX = point.pageX - this.lastPointX;
43547        this.lastPointX = point.pageX;
43548
43549        deltaY = point.pageY - this.lastPointY;
43550        this.lastPointY = point.pageY;
43551
43552        newX = this.x + deltaX;
43553        newY = this.y + deltaY;
43554
43555        this._pos(newX, newY);
43556
43557// INSERT POINT: indicator._move
43558
43559        e.preventDefault();
43560        e.stopPropagation();
43561    },
43562
43563    _end: function (e) {
43564        if ( !this.initiated ) {
43565            return;
43566        }
43567
43568        this.initiated = false;
43569
43570        e.preventDefault();
43571        e.stopPropagation();
43572
43573        utils.removeEvent(window, 'touchmove', this);
43574        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
43575        utils.removeEvent(window, 'mousemove', this);
43576
43577        if ( this.scroller.options.snap ) {
43578            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
43579
43580            var time = this.options.snapSpeed || Math.max(
43581                    Math.max(
43582                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
43583                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
43584                    ), 300);
43585
43586            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
43587                this.scroller.directionX = 0;
43588                this.scroller.directionY = 0;
43589                this.scroller.currentPage = snap;
43590                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
43591            }
43592        }
43593
43594        if ( this.moved ) {
43595            this.scroller._execEvent('scrollEnd');
43596        }
43597    },
43598
43599    transitionTime: function (time) {
43600        time = time || 0;
43601        var durationProp = utils.style.transitionDuration;
43602        if(!durationProp) {
43603            return;
43604        }
43605
43606        this.indicatorStyle[durationProp] = time + 'ms';
43607
43608        if ( !time && utils.isBadAndroid ) {
43609            this.indicatorStyle[durationProp] = '0.0001ms';
43610            // remove 0.0001ms
43611            var self = this;
43612            rAF(function() {
43613                if(self.indicatorStyle[durationProp] === '0.0001ms') {
43614                    self.indicatorStyle[durationProp] = '0s';
43615                }
43616            });
43617        }
43618    },
43619
43620    transitionTimingFunction: function (easing) {
43621        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
43622    },
43623
43624    refresh: function () {
43625        this.transitionTime();
43626
43627        if ( this.options.listenX && !this.options.listenY ) {
43628            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
43629        } else if ( this.options.listenY && !this.options.listenX ) {
43630            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
43631        } else {
43632            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
43633        }
43634
43635        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
43636            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
43637            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
43638
43639            if ( this.options.defaultScrollbars && this.options.customStyle ) {
43640                if ( this.options.listenX ) {
43641                    this.wrapper.style.right = '8px';
43642                } else {
43643                    this.wrapper.style.bottom = '8px';
43644                }
43645            }
43646        } else {
43647            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
43648            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
43649
43650            if ( this.options.defaultScrollbars && this.options.customStyle ) {
43651                if ( this.options.listenX ) {
43652                    this.wrapper.style.right = '2px';
43653                } else {
43654                    this.wrapper.style.bottom = '2px';
43655                }
43656            }
43657        }
43658
43659        var r = this.wrapper.offsetHeight;  // force refresh
43660
43661        if ( this.options.listenX ) {
43662            this.wrapperWidth = this.wrapper.clientWidth;
43663            if ( this.options.resize ) {
43664                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
43665                this.indicatorStyle.width = this.indicatorWidth + 'px';
43666            } else {
43667                this.indicatorWidth = this.indicator.clientWidth;
43668            }
43669
43670            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
43671
43672            if ( this.options.shrink == 'clip' ) {
43673                this.minBoundaryX = -this.indicatorWidth + 8;
43674                this.maxBoundaryX = this.wrapperWidth - 8;
43675            } else {
43676                this.minBoundaryX = 0;
43677                this.maxBoundaryX = this.maxPosX;
43678            }
43679
43680            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
43681        }
43682
43683        if ( this.options.listenY ) {
43684            this.wrapperHeight = this.wrapper.clientHeight;
43685            if ( this.options.resize ) {
43686                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
43687                this.indicatorStyle.height = this.indicatorHeight + 'px';
43688            } else {
43689                this.indicatorHeight = this.indicator.clientHeight;
43690            }
43691
43692            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
43693
43694            if ( this.options.shrink == 'clip' ) {
43695                this.minBoundaryY = -this.indicatorHeight + 8;
43696                this.maxBoundaryY = this.wrapperHeight - 8;
43697            } else {
43698                this.minBoundaryY = 0;
43699                this.maxBoundaryY = this.maxPosY;
43700            }
43701
43702            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
43703            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
43704        }
43705
43706        this.updatePosition();
43707    },
43708
43709    updatePosition: function () {
43710        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
43711            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
43712
43713        if ( !this.options.ignoreBoundaries ) {
43714            if ( x < this.minBoundaryX ) {
43715                if ( this.options.shrink == 'scale' ) {
43716                    this.width = Math.max(this.indicatorWidth + x, 8);
43717                    this.indicatorStyle.width = this.width + 'px';
43718                }
43719                x = this.minBoundaryX;
43720            } else if ( x > this.maxBoundaryX ) {
43721                if ( this.options.shrink == 'scale' ) {
43722                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
43723                    this.indicatorStyle.width = this.width + 'px';
43724                    x = this.maxPosX + this.indicatorWidth - this.width;
43725                } else {
43726                    x = this.maxBoundaryX;
43727                }
43728            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
43729                this.width = this.indicatorWidth;
43730                this.indicatorStyle.width = this.width + 'px';
43731            }
43732
43733            if ( y < this.minBoundaryY ) {
43734                if ( this.options.shrink == 'scale' ) {
43735                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
43736                    this.indicatorStyle.height = this.height + 'px';
43737                }
43738                y = this.minBoundaryY;
43739            } else if ( y > this.maxBoundaryY ) {
43740                if ( this.options.shrink == 'scale' ) {
43741                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
43742                    this.indicatorStyle.height = this.height + 'px';
43743                    y = this.maxPosY + this.indicatorHeight - this.height;
43744                } else {
43745                    y = this.maxBoundaryY;
43746                }
43747            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
43748                this.height = this.indicatorHeight;
43749                this.indicatorStyle.height = this.height + 'px';
43750            }
43751        }
43752
43753        this.x = x;
43754        this.y = y;
43755
43756        if ( this.scroller.options.useTransform ) {
43757            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
43758        } else {
43759            this.indicatorStyle.left = x + 'px';
43760            this.indicatorStyle.top = y + 'px';
43761        }
43762    },
43763
43764    _pos: function (x, y) {
43765        if ( x < 0 ) {
43766            x = 0;
43767        } else if ( x > this.maxPosX ) {
43768            x = this.maxPosX;
43769        }
43770
43771        if ( y < 0 ) {
43772            y = 0;
43773        } else if ( y > this.maxPosY ) {
43774            y = this.maxPosY;
43775        }
43776
43777        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
43778        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
43779
43780        this.scroller.scrollTo(x, y);
43781    },
43782
43783    fade: function (val, hold) {
43784        if ( hold && !this.visible ) {
43785            return;
43786        }
43787
43788        clearTimeout(this.fadeTimeout);
43789        this.fadeTimeout = null;
43790
43791        var time = val ? 250 : 500,
43792            delay = val ? 0 : 300;
43793
43794        val = val ? '1' : '0';
43795
43796        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
43797
43798        this.fadeTimeout = setTimeout((function (val) {
43799            this.wrapperStyle.opacity = val;
43800            this.visible = +val;
43801        }).bind(this, val), delay);
43802    }
43803};
43804
43805IScroll.utils = utils;
43806
43807if ( typeof module != 'undefined' && module.exports ) {
43808    module.exports = IScroll;
43809} else if ( typeof define == 'function' && define.amd ) {
43810        define( function () { return IScroll; } );
43811} else {
43812    window.IScroll = IScroll;
43813}
43814
43815})(window, document, Math);
43816/*!
43817 * fullPage 2.9.4
43818 * https://github.com/alvarotrigo/fullPage.js
43819 * @license MIT licensed
43820 *
43821 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
43822 */
43823(function(global, factory) {
43824    'use strict';
43825    if (typeof define === 'function' && define.amd) {
43826        define(['jquery'], function($) {
43827          return factory($, global, global.document, global.Math);
43828        });
43829    } else if (typeof exports === "object" && exports) {
43830        module.exports = factory(require('jquery'), global, global.document, global.Math);
43831    } else {
43832        factory(jQuery, global, global.document, global.Math);
43833    }
43834})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
43835    'use strict';
43836
43837    // keeping central set of classnames and selectors
43838    var WRAPPER =               'fullpage-wrapper';
43839    var WRAPPER_SEL =           '.' + WRAPPER;
43840
43841    // slimscroll
43842    var SCROLLABLE =            'fp-scrollable';
43843    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
43844
43845    // util
43846    var RESPONSIVE =            'fp-responsive';
43847    var NO_TRANSITION =         'fp-notransition';
43848    var DESTROYED =             'fp-destroyed';
43849    var ENABLED =               'fp-enabled';
43850    var VIEWING_PREFIX =        'fp-viewing';
43851    var ACTIVE =                'active';
43852    var ACTIVE_SEL =            '.' + ACTIVE;
43853    var COMPLETELY =            'fp-completely';
43854    var COMPLETELY_SEL =        '.' + COMPLETELY;
43855
43856    // section
43857    var SECTION_DEFAULT_SEL =   '.section';
43858    var SECTION =               'fp-section';
43859    var SECTION_SEL =           '.' + SECTION;
43860    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
43861    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
43862    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
43863    var TABLE_CELL =            'fp-tableCell';
43864    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
43865    var AUTO_HEIGHT =           'fp-auto-height';
43866    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
43867    var NORMAL_SCROLL =         'fp-normal-scroll';
43868    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
43869
43870    // section nav
43871    var SECTION_NAV =           'fp-nav';
43872    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
43873    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
43874    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
43875    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
43876
43877    // slide
43878    var SLIDE_DEFAULT_SEL =     '.slide';
43879    var SLIDE =                 'fp-slide';
43880    var SLIDE_SEL =             '.' + SLIDE;
43881    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
43882    var SLIDES_WRAPPER =        'fp-slides';
43883    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
43884    var SLIDES_CONTAINER =      'fp-slidesContainer';
43885    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
43886    var TABLE =                 'fp-table';
43887
43888    // slide nav
43889    var SLIDES_NAV =            'fp-slidesNav';
43890    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
43891    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
43892    var SLIDES_ARROW =          'fp-controlArrow';
43893    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
43894    var SLIDES_PREV =           'fp-prev';
43895    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
43896    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
43897    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
43898    var SLIDES_NEXT =           'fp-next';
43899    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
43900    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
43901    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
43902
43903    var $window = $(window);
43904    var $document = $(document);
43905
43906    // Default options for iScroll.js used when using scrollOverflow
43907    var iscrollOptions = {
43908        scrollbars: true,
43909        mouseWheel: true,
43910        hideScrollbars: false,
43911        fadeScrollbars: false,
43912        disableMouse: true,
43913        interactiveScrollbars: true,
43914        bounce: false,
43915    };
43916
43917    $.fn.fullpage = function(options) {
43918        //only once my friend!
43919        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
43920
43921        // common jQuery objects
43922        var $htmlBody = $('html, body');
43923        var $body = $('body');
43924
43925        var FP = $.fn.fullpage;
43926
43927        // Creating some defaults, extending them with any options that were provided
43928        options = $.extend({
43929            //navigation
43930            menu: false,
43931            anchors:[],
43932            lockAnchors: false,
43933            navigation: false,
43934            navigationPosition: 'right',
43935            navigationTooltips: [],
43936            showActiveTooltip: false,
43937            slidesNavigation: false,
43938            slidesNavPosition: 'bottom',
43939            scrollBar: false,
43940            hybrid: false,
43941
43942            //scrolling
43943            css3: true,
43944            scrollingSpeed: 700,
43945            autoScrolling: true,
43946            fitToSection: true,
43947            fitToSectionDelay: 1000,
43948            easing: 'easeInOutCubic',
43949            easingcss3: 'ease',
43950            loopBottom: false,
43951            loopTop: false,
43952            loopHorizontal: true,
43953            continuousVertical: false,
43954            continuousHorizontal: false,
43955            scrollHorizontally: false,
43956            interlockedSlides: false,
43957            dragAndMove: false,
43958            offsetSections: false,
43959            resetSliders: false,
43960            fadingEffect: false,
43961            normalScrollElements: null,
43962            scrollOverflow: false,
43963            scrollOverflowReset: false,
43964            scrollOverflowHandler: iscrollHandler,
43965            scrollOverflowOptions: null,
43966            touchSensitivity: 5,
43967            normalScrollElementTouchThreshold: 5,
43968            bigSectionsDestination: null,
43969
43970            //Accessibility
43971            keyboardScrolling: true,
43972            animateAnchor: true,
43973            recordHistory: true,
43974
43975            //design
43976            controlArrows: true,
43977            controlArrowColor: '#fff',
43978            verticalCentered: true,
43979            sectionsColor : [],
43980            paddingTop: 0,
43981            paddingBottom: 0,
43982            fixedElements: null,
43983            responsive: 0, //backwards compabitility with responsiveWiddth
43984            responsiveWidth: 0,
43985            responsiveHeight: 0,
43986            responsiveSlides: false,
43987            parallax: false,
43988            parallaxOptions: {
43989                type: 'reveal',
43990                percentage: 62,
43991                property: 'translate'
43992            },
43993
43994            //Custom selectors
43995            sectionSelector: SECTION_DEFAULT_SEL,
43996            slideSelector: SLIDE_DEFAULT_SEL,
43997
43998            //events
43999            afterLoad: null,
44000            onLeave: null,
44001            afterRender: null,
44002            afterResize: null,
44003            afterReBuild: null,
44004            afterSlideLoad: null,
44005            onSlideLeave: null,
44006            afterResponsive: null,
44007
44008            lazyLoading: true
44009        }, options);
44010
44011        //flag to avoid very fast sliding for landscape sliders
44012        var slideMoving = false;
44013
44014        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
44015        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
44016        var container = $(this);
44017        var windowsHeight = $window.height();
44018        var isResizing = false;
44019        var isWindowFocused = true;
44020        var lastScrolledDestiny;
44021        var lastScrolledSlide;
44022        var canScroll = true;
44023        var scrollings = [];
44024        var controlPressed;
44025        var startingSection;
44026        var isScrollAllowed = {};
44027        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
44028        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
44029        var MSPointer = getMSPointer();
44030        var events = {
44031            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
44032            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
44033        };
44034
44035        //cheks for passive event support
44036        //added by Uncode from new fullPage updates
44037        var g_supportsPassive = false;
44038        try {
44039          var opts = Object.defineProperty({}, 'passive', {
44040            get: function() {
44041              g_supportsPassive = true;
44042            }
44043          });
44044          window.addEventListener("testPassive", null, opts);
44045          window.removeEventListener("testPassive", null, opts);
44046        } catch (e) {}
44047
44048        //timeouts
44049        var resizeId;
44050        var afterSectionLoadsId;
44051        var afterSlideLoadsId;
44052        var scrollId;
44053        var scrollId2;
44054        var keydownId;
44055        var originals = $.extend(true, {}, options); //deep copy
44056
44057        //Uncode addition
44058        var $masthead = $('#masthead');
44059        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
44060        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
44061        var bodyBorder = UNCODE.bodyBorder;
44062        var adminBarHeight = UNCODE.adminBarHeight;
44063
44064        displayWarnings();
44065
44066        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
44067        iscrollOptions.click = isTouch; // see #2035
44068
44069        //extending iScroll options with the user custom ones
44070        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
44071
44072        //easeInOutCubic animation included in the plugin
44073        $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}});
44074
44075        /**
44076        * Sets the autoScroll option.
44077        * It changes the scroll bar visibility and the history of the site as a result.
44078        */
44079        function setAutoScrolling(value, type){
44080            //removing the transformation
44081            if(!value){
44082                silentScroll(0);
44083            }
44084
44085            setVariableState('autoScrolling', value, type);
44086
44087            var element = $(SECTION_ACTIVE_SEL);
44088
44089            if(options.autoScrolling && !options.scrollBar){
44090                $htmlBody.css({
44091                    'overflow' : 'hidden !important',
44092                    'height' : '100%'
44093                });
44094
44095                //Uncode addition
44096                //setRecordHistory(originals.recordHistory, 'internal');
44097
44098                //for IE touch devices
44099                container.css({
44100                    '-ms-touch-action': 'none',
44101                    'touch-action': 'none'
44102                });
44103
44104                if(element.length){
44105                    //moving the container up
44106                    silentScroll(element.position().top);
44107                }
44108
44109            }else{
44110                $htmlBody.css({
44111                    'overflow' : 'visible !important',
44112                    'height' : 'initial'
44113                });
44114
44115                //Uncode addition
44116                //setRecordHistory(false, 'internal');
44117
44118                //for IE touch devices
44119                container.css({
44120                    '-ms-touch-action': '',
44121                    'touch-action': ''
44122                });
44123
44124                //scrolling the page to the section with no animation
44125                if (element.length) {
44126                    $htmlBody.scrollTop(element.position().top);
44127                }
44128            }
44129        }
44130
44131        /**
44132        * Defines wheter to record the history for each hash change in the URL.
44133        */
44134        function setRecordHistory(value, type){
44135            setVariableState('recordHistory', value, type);
44136        }
44137
44138        /**
44139        * Defines the scrolling speed
44140        */
44141        function setScrollingSpeed(value, type){
44142            setVariableState('scrollingSpeed', value, type);
44143        }
44144
44145        /**
44146        * Sets fitToSection
44147        */
44148        function setFitToSection(value, type){
44149            setVariableState('fitToSection', value, type);
44150        }
44151
44152        /**
44153        * Sets lockAnchors
44154        */
44155        function setLockAnchors(value){
44156            options.lockAnchors = value;
44157        }
44158
44159        /**
44160        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
44161        */
44162        function setMouseWheelScrolling(value){
44163            if(value){
44164                addMouseWheelHandler();
44165                addMiddleWheelHandler();
44166            }else{
44167                removeMouseWheelHandler();
44168                removeMiddleWheelHandler();
44169            }
44170        }
44171
44172        /**
44173        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
44174        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
44175        *
44176        * @param directions string containing the direction or directions separated by comma.
44177        */
44178        function setAllowScrolling(value, directions){
44179            if(typeof directions !== 'undefined'){
44180                directions = directions.replace(/ /g,'').split(',');
44181
44182                $.each(directions, function (index, direction){
44183                    setIsScrollAllowed(value, direction, 'm');
44184                });
44185            }
44186            else if(value){
44187                setMouseWheelScrolling(true);
44188                addTouchHandler();
44189            }else{
44190                setMouseWheelScrolling(false);
44191                removeTouchHandler();
44192            }
44193        }
44194
44195        /**
44196        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
44197        */
44198        function setKeyboardScrolling(value, directions){
44199            if(typeof directions !== 'undefined'){
44200                directions = directions.replace(/ /g,'').split(',');
44201
44202                $.each(directions, function (index, direction){
44203                    setIsScrollAllowed(value, direction, 'k');
44204                });
44205            }else{
44206                options.keyboardScrolling = value;
44207            }
44208        }
44209
44210        /**
44211        * Moves the page up one section.
44212        */
44213        function moveSectionUp(){
44214            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
44215
44216            //looping to the bottom if there's no more sections above
44217            if (!prev.length && (options.loopTop || options.continuousVertical)) {
44218                prev = $(SECTION_SEL).last();
44219            }
44220
44221            if (prev.length) {
44222                scrollPage(prev, null, true);
44223            }
44224        }
44225
44226        /**
44227        * Moves the page down one section.
44228        */
44229        function moveSectionDown(){
44230            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
44231
44232            //looping to the top if there's no more sections below
44233            if(!next.length &&
44234                (options.loopBottom || options.continuousVertical)){
44235                next = $(SECTION_SEL).first();
44236            }
44237
44238            if(next.length){
44239                scrollPage(next, null, false);
44240            }
44241        }
44242
44243        /**
44244        * Moves the page to the given section and slide with no animation.
44245        * Anchors or index positions can be used as params.
44246        */
44247        function silentMoveTo(sectionAnchor, slideAnchor){
44248            setScrollingSpeed (0, 'internal');
44249            moveTo(sectionAnchor, slideAnchor);
44250            setScrollingSpeed (originals.scrollingSpeed, 'internal');
44251        }
44252
44253        /**
44254        * Moves the page to the given section and slide.
44255        * Anchors or index positions can be used as params.
44256        */
44257        function moveTo(sectionAnchor, slideAnchor){
44258            var destiny = getSectionByAnchor(sectionAnchor);
44259
44260            if (typeof slideAnchor !== 'undefined'){
44261                scrollPageAndSlide(sectionAnchor, slideAnchor);
44262            }else if(destiny.length > 0){
44263                scrollPage(destiny);
44264            }
44265        }
44266
44267        /**
44268        * Slides right the slider of the active section.
44269        * Optional `section` param.
44270        */
44271        function moveSlideRight(section){
44272            moveSlide('right', section);
44273        }
44274
44275        /**
44276        * Slides left the slider of the active section.
44277        * Optional `section` param.
44278        */
44279        function moveSlideLeft(section){
44280            moveSlide('left', section);
44281        }
44282
44283        /**
44284         * When resizing is finished, we adjust the slides sizes and positions
44285         */
44286        function reBuild(resizing){
44287            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
44288
44289            isResizing = true;
44290
44291            windowsHeight = $window.height();  //updating global var
44292
44293            $(SECTION_SEL).each(function(){
44294                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
44295                var slides = $(this).find(SLIDE_SEL);
44296
44297                //adjusting the height of the table-cell for IE and Firefox
44298                if(options.verticalCentered){
44299                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
44300                }
44301
44302                $(this).css('height', windowsHeight + 'px');
44303
44304                //resizing the scrolling divs
44305                if(options.scrollOverflow){
44306                    if(slides.length){
44307                        slides.each(function(){
44308                            createScrollBar($(this));
44309                        });
44310                    }else{
44311                        createScrollBar($(this));
44312                    }
44313                }
44314
44315                //adjusting the position fo the FULL WIDTH slides...
44316                if (slides.length > 1) {
44317                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
44318                }
44319            });
44320
44321            var activeSection = $(SECTION_ACTIVE_SEL);
44322            var sectionIndex = activeSection.index(SECTION_SEL);
44323
44324            //isn't it the first section?
44325            if(sectionIndex){
44326                //adjusting the position for the current section
44327                silentMoveTo(sectionIndex + 1);
44328            }
44329
44330            isResizing = false;
44331            // Uncode change
44332            // $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
44333            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container, getTableHeight());
44334            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
44335        }
44336
44337        /**
44338        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
44339        * are smaller than the set limit values.
44340        */
44341        function setResponsive(active){
44342            var isResponsive = $body.hasClass(RESPONSIVE);
44343
44344            if(active){
44345                if(!isResponsive){
44346                    setAutoScrolling(false, 'internal');
44347                    setFitToSection(false, 'internal');
44348                    $(SECTION_NAV_SEL).hide();
44349                    $body.addClass(RESPONSIVE);
44350                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
44351                }
44352            }
44353            else if(isResponsive){
44354                setAutoScrolling(originals.autoScrolling, 'internal');
44355                setFitToSection(originals.autoScrolling, 'internal');
44356                $(SECTION_NAV_SEL).show();
44357                $body.removeClass(RESPONSIVE);
44358                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
44359            }
44360        }
44361
44362        if($(this).length){
44363            //public functions
44364            FP.setAutoScrolling = setAutoScrolling;
44365            FP.setRecordHistory = setRecordHistory;
44366            FP.setScrollingSpeed = setScrollingSpeed;
44367            FP.setFitToSection = setFitToSection;
44368            FP.setLockAnchors = setLockAnchors;
44369            FP.setMouseWheelScrolling = setMouseWheelScrolling;
44370            FP.setAllowScrolling = setAllowScrolling;
44371            FP.setKeyboardScrolling = setKeyboardScrolling;
44372            FP.moveSectionUp = moveSectionUp;
44373            FP.moveSectionDown = moveSectionDown;
44374            FP.silentMoveTo = silentMoveTo;
44375            FP.moveTo = moveTo;
44376            FP.moveSlideRight = moveSlideRight;
44377            FP.moveSlideLeft = moveSlideLeft;
44378            FP.fitToSection = fitToSection;
44379            FP.reBuild = reBuild;
44380            FP.setResponsive = setResponsive;
44381            FP.destroy = destroy;
44382
44383            init();
44384
44385            bindEvents();
44386        }
44387
44388        function init(){
44389            //if css3 is not supported, it will use jQuery animations
44390            if(options.css3){
44391                options.css3 = support3d();
44392            }
44393
44394            options.scrollBar = options.scrollBar || options.hybrid;
44395
44396            setOptionsFromDOM();
44397            prepareDom();
44398            setAllowScrolling(true);
44399            setAutoScrolling(options.autoScrolling, 'internal');
44400            responsive();
44401
44402            //setting the class for the body element
44403            setBodyClass();
44404
44405            //Uncode addition
44406            // if(document.readyState === 'complete'){
44407            //     scrollToAnchor();
44408            // }
44409            // $window.on('load', scrollToAnchor);
44410        }
44411
44412        function bindEvents(){
44413            $window
44414                //when scrolling...
44415                //.on('scroll', scrollHandler)
44416
44417                //detecting any change on the URL to scroll to the given anchor link
44418                //(a way to detect back history button as we play with the hashes on the URL)
44419                .on('hashchange', hashChangeHandler)
44420
44421                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
44422                .blur(blurHandler)
44423
44424                //when resizing the site, we adjust the heights of the sections, slimScroll...
44425                .resize(resizeHandler);
44426
44427            $document
44428                //Sliding with arrow keys, both, vertical and horizontal
44429                .keydown(keydownHandler)
44430
44431                //to prevent scrolling while zooming
44432                .keyup(keyUpHandler)
44433
44434                //Scrolls to the section when clicking the navigation bullet
44435                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
44436
44437                //Scrolls the slider to the given slide destination for the given section
44438                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
44439
44440                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
44441
44442            //Scrolling horizontally when clicking on the slider controls.
44443            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
44444
44445            /**
44446            * Applying normalScroll elements.
44447            * Ignoring the scrolls over the specified selectors.
44448            */
44449            if(options.normalScrollElements){
44450                $document.on('mouseenter', options.normalScrollElements, function () {
44451                    setMouseWheelScrolling(false);
44452                });
44453
44454                $document.on('mouseleave', options.normalScrollElements, function(){
44455                    setMouseWheelScrolling(true);
44456                });
44457            }
44458        }
44459
44460        /**
44461        * Setting options from DOM elements if they are not provided.
44462        */
44463        function setOptionsFromDOM(){
44464            var sections = container.find(options.sectionSelector);
44465
44466            //no anchors option? Checking for them in the DOM attributes
44467            if(!options.anchors.length){
44468                options.anchors = sections.filter('[data-anchor]').map(function(){
44469                    return $(this).data('anchor').toString();
44470                }).get();
44471            }
44472
44473            //no tooltips option? Checking for them in the DOM attributes
44474            if(!options.navigationTooltips.length){
44475                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
44476                    return $(this).data('tooltip').toString();
44477                }).get();
44478            }
44479        }
44480
44481        /**
44482        * Works over the DOM structure to set it up for the current fullpage options.
44483        */
44484        function prepareDom(){
44485            container.css({
44486                'height': '100%',
44487                'position': 'relative'
44488            });
44489
44490            //adding a class to recognize the container internally in the code
44491            container.addClass(WRAPPER);
44492            $('html').addClass(ENABLED);
44493
44494            windowsHeight = $window.height();
44495
44496            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
44497
44498            addInternalSelectors();
44499
44500             //styling the sections / slides / menu
44501            $(SECTION_SEL).each(function(index){
44502                var section = $(this);
44503                var slides = section.find(SLIDE_SEL);
44504                var numSlides = slides.length;
44505
44506                styleSection(section, index);
44507                styleMenu(section, index);
44508
44509                // if there's any slide
44510                if (numSlides > 0) {
44511                    styleSlides(section, slides, numSlides);
44512                }else{
44513                    if(options.verticalCentered){
44514                        addTableClass(section);
44515                    }
44516                }
44517            });
44518
44519            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
44520            if(options.fixedElements && options.css3){
44521                $(options.fixedElements).appendTo($body);
44522            }
44523
44524            //vertical centered of the navigation + active bullet
44525            if(options.navigation){
44526                addVerticalNavigation();
44527            }
44528
44529            enableYoutubeAPI();
44530
44531            if(options.scrollOverflow){
44532                if(document.readyState === 'complete'){
44533                    createScrollBarHandler();
44534                }
44535                //after DOM and images are loaded
44536                $window.on('load', createScrollBarHandler);
44537            }else{
44538                afterRenderActions();
44539            }
44540        }
44541
44542        /**
44543        * Styles the horizontal slides for a section.
44544        */
44545        function styleSlides(section, slides, numSlides){
44546            var sliderWidth = numSlides * 100;
44547            var slideWidth = 100 / numSlides;
44548
44549            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
44550            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
44551
44552            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
44553
44554            if(numSlides > 1){
44555                if(options.controlArrows){
44556                    createSlideArrows(section);
44557                }
44558
44559                if(options.slidesNavigation){
44560                    addSlidesNavigation(section, numSlides);
44561                }
44562            }
44563
44564            slides.each(function(index) {
44565                $(this).css('width', slideWidth + '%');
44566
44567                if(options.verticalCentered){
44568                    addTableClass($(this));
44569                }
44570            });
44571
44572            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
44573
44574            //if the slide won't be an starting point, the default will be the first one
44575            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
44575ide by default.
44576            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
44577                silentLandscapeScroll(startingSlide, 'internal');
44578            }else{
44579                slides.eq(0).addClass(ACTIVE);
44580            }
44581        }
44582
44583        /**
44584        * Styling vertical sections
44585        */
44586        function styleSection(section, index){
44587            //if no active section is defined, the 1st one will be the default one
44588            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
44589                section.addClass(ACTIVE);
44590            }
44591            startingSection = $(SECTION_ACTIVE_SEL);
44592
44593            section.css('height', windowsHeight + 'px');
44594
44595            if(options.paddingTop){
44596                section.css('padding-top', options.paddingTop);
44597            }
44598
44599            if(options.paddingBottom){
44600                section.css('padding-bottom', options.paddingBottom);
44601            }
44602
44603            if (typeof options.sectionsColor[index] !==  'undefined') {
44604                section.css('background-color', options.sectionsColor[index]);
44605            }
44606
44607            if (typeof options.anchors[index] !== 'undefined') {
44608                section.attr('data-anchor', options.anchors[index]);
44609            }
44610        }
44611
44612        /**
44613        * Sets the data-anchor attributes to the menu elements and activates the current one.
44614        */
44615        function styleMenu(section, index){
44616            if (typeof options.anchors[index] !== 'undefined') {
44617                //activating the menu / nav element on load
44618                if(section.hasClass(ACTIVE)){
44619                    activateMenuAndNav(options.anchors[index], index);
44620                }
44621            }
44622
44623            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
44624            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
44625                $(options.menu).appendTo($body);
44626            }
44627        }
44628
44629        /**
44630        * Adds internal classes to be able to provide customizable selectors
44631        * keeping the link with the style sheet.
44632        */
44633        function addInternalSelectors(){
44634            container.find(options.sectionSelector).addClass(SECTION);
44635            container.find(options.slideSelector).addClass(SLIDE);
44636        }
44637
44638        /**
44639        * Creates the control arrows for the given section
44640        */
44641        function createSlideArrows(section){
44642            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
44643
44644            if(options.controlArrowColor!='#fff'){
44645                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
44646                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
44647            }
44648
44649            if(!options.loopHorizontal){
44650                section.find(SLIDES_ARROW_PREV_SEL).hide();
44651            }
44652        }
44653
44654        /**
44655        * Creates a vertical navigation bar.
44656        */
44657        function addVerticalNavigation(){
44658            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
44659            var nav = $(SECTION_NAV_SEL);
44660
44661            nav.addClass(function() {
44662                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
44663            });
44664
44665            for (var i = 0; i < $(SECTION_SEL).length; i++) {
44666                var link = '';
44667                if (options.anchors.length) {
44668                    link = options.anchors[i];
44669                }
44670
44671                var li = '<li><a href="#' + link + '"><span></span></a>';
44672
44673                // Only add tooltip if needed (defined by user)
44674                var tooltip = options.navigationTooltips[i];
44675
44676                if (typeof tooltip !== 'undefined' && tooltip !== '') {
44677                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
44678                }
44679
44680                li += '</li>';
44681
44682                nav.find('ul').append(li);
44683            }
44684
44685            //centering it vertically
44686            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
44687
44688            //activating the current active section
44689            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
44690        }
44691
44692        /**
44693        * Creates the slim scroll scrollbar for the sections and slides inside them.
44694        */
44695        function createScrollBarHandler(){
44696            $(SECTION_SEL).each(function(){
44697                var slides = $(this).find(SLIDE_SEL);
44698
44699                if(slides.length){
44700                    slides.each(function(){
44701                        createScrollBar($(this));
44702                    });
44703                }else{
44704                    createScrollBar($(this));
44705                }
44706
44707            });
44708            afterRenderActions();
44709        }
44710
44711        /*
44712        * Enables the Youtube videos API so we can control their flow if necessary.
44713        */
44714        function enableYoutubeAPI(){
44715            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
44716                addURLParam($(this), 'enablejsapi=1');
44717            });
44718        }
44719
44720        /**
44721        * Adds a new parameter and its value to the `src` of a given element
44722        */
44723        function addURLParam(element, newParam){
44724            var originalSrc = element.attr('src');
44725            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
44726        }
44727
44728        /*
44729        * Returns the prefix sign to use for a new parameter in an existen URL.
44730        *
44731        * @return {String}  ? | &
44732        */
44733        function getUrlParamSign(url){
44734            return ( !/\?/.test( url ) ) ? '?' : '&';
44735        }
44736
44737        /**
44738        * Actions and callbacks to fire afterRender
44739        */
44740        function afterRenderActions(){
44741            var section = $(SECTION_ACTIVE_SEL);
44742
44743            section.addClass(COMPLETELY);
44744
44745            if(options.scrollOverflowHandler.afterRender){
44746                options.scrollOverflowHandler.afterRender(section);
44747            }
44748            lazyLoad(section);
44749            playMedia(section);
44750            options.scrollOverflowHandler.afterLoad();
44751
44752            if(isDestinyTheStartingSection()){
44753                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
44754            }
44755
44756            // Uncode change
44757            // $.isFunction( options.afterRender ) && options.afterRender.call(container);
44758            $.isFunction( options.afterRender ) && options.afterRender.call(container, getTableHeight());
44759        }
44760
44761        /**
44762        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
44763        */
44764        function isDestinyTheStartingSection(){
44765            var anchors =  window.location.hash.replace('#', '').split('/');
44766            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
44767
44768            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
44769        }
44770
44771
44772        var isScrolling = false;
44773        var lastScroll = 0;
44774
44775        //when scrolling...
44776        function scrollHandler(){
44777            var currentSection;
44778
44779            if(!options.autoScrolling || options.scrollBar){
44780                var currentScroll = $window.scrollTop();
44781                var scrollDirection = getScrollDirection(currentScroll);
44782                var visibleSectionIndex = 0;
44783                var screen_mid = currentScroll + ($window.height() / 2.0);
44784                var isAtBottom = $body.height() - $window.height() === currentScroll;
44785                var sections =  document.querySelectorAll(SECTION_SEL);
44786
44787                //when using `auto-height` for a small last section it won't be centered in the viewport
44788                if(isAtBottom){
44789                    visibleSectionIndex = sections.length - 1;
44790                }
44791                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
44792                else if(!currentScroll){
44793                    visibleSectionIndex = 0;
44794                }
44795
44796                //taking the section which is showing more content in the viewport
44797                else{
44798                    for (var i = 0; i < sections.length; ++i) {
44799                        var section = sections[i];
44800
44801                        // Pick the the last section which passes the middle line of the screen.
44802                        if (section.offsetTop <= screen_mid)
44803                        {
44804                            visibleSectionIndex = i;
44805                        }
44806                    }
44807                }
44808
44809                if(isCompletelyInViewPort(scrollDirection)){
44810                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
44811                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
44812                    }
44813                }
44814
44815                //geting the last one, the current one on the screen
44816                currentSection = $(sections).eq(visibleSectionIndex);
44817
44818                //setting the visible section as active when manually scrolling
44819                //executing only once the first time we reach the section
44820                if(!currentSection.hasClass(ACTIVE)){
44821                    isScrolling = true;
44822                    var leavingSection = $(SECTION_ACTIVE_SEL);
44823                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
44824                    var yMovement = getYmovement(currentSection);
44825                    var anchorLink  = currentSection.data('anchor');
44826                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
44827                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
44828                    var slideIndex;
44829                    var slideAnchorLink;
44830
44831                    if(activeSlide.length){
44832                        slideAnchorLink = activeSlide.data('anchor');
44833                        slideIndex = activeSlide.index();
44834                    }
44835
44836                    if(canScroll){
44837                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
44838
44839                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
44840                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
44841
44842                        stopMedia(leavingSection);
44843                        lazyLoad(currentSection);
44844                        playMedia(currentSection);
44845
44846                        activateMenuAndNav(anchorLink, sectionIndex - 1);
44847
44848                        if(options.anchors.length){
44849                            //needed to enter in hashChange event when using the menu with anchor links
44850                            lastScrolledDestiny = anchorLink;
44851                        }
44852                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
44853                    }
44854
44855                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
44856                    clearTimeout(scrollId);
44857                    scrollId = setTimeout(function(){
44858                        isScrolling = false;
44859                    }, 100);
44860                }
44861
44862                if(options.fitToSection){
44863                    //for the auto adjust of the viewport to fit a whole section
44864                    clearTimeout(scrollId2);
44865
44866                    scrollId2 = setTimeout(function(){
44867                        //checking it again in case it changed during the delay
44868                        if(options.fitToSection){
44869                            fitToSection();
44870                        }
44871                    }, options.fitToSectionDelay);
44872                }
44873            }
44874        }
44875
44876        /**
44877        * Fits the site to the nearest active section
44878        */
44879        function fitToSection(){
44880            //checking fitToSection again in case it was set to false before the timeout delay
44881            if(canScroll){
44882                //allows to scroll to an active section and
44883                //if the section is already active, we prevent firing callbacks
44884                isResizing = true;
44885
44886                scrollPage($(SECTION_ACTIVE_SEL));
44887                isResizing = false;
44888            }
44889        }
44890
44891        /**
44892        * Determines whether the active section has seen in its whole or not.
44893        */
44894        function isCompletelyInViewPort(movement){
44895            var top = $(SECTION_ACTIVE_SEL).position().top;
44896            var bottom = top + $window.height();
44897
44898            if(movement == 'up'){
44899                return bottom >= ($window.scrollTop() + $window.height());
44900            }
44901            return top <= $window.scrollTop();
44902        }
44903
44904        /**
44905        * Gets the directon of the the scrolling fired by the scroll event.
44906        */
44907        function getScrollDirection(currentScroll){
44908            var direction = currentScroll > lastScroll ? 'down' : 'up';
44909
44910            lastScroll = currentScroll;
44911
44912            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
44913            previousDestTop = currentScroll;
44914
44915            return direction;
44916        }
44917
44918        /**
44919        * Determines the way of scrolling up or down:
44920        * by 'automatically' scrolling a section or by using the default and normal scrolling.
44921        */
44922        function scrolling(type, scrollable){
44923            if (!isScrollAllowed.m[type]){
44924                return;
44925            }
44926            var check = (type === 'down') ? 'bottom' : 'top';
44927            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
44928
44929            if(scrollable.length > 0 ){
44930                //is the scrollbar at the start/end of the scroll?
44931                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
44932                    scrollSection();
44933                }else{
44934                    return true;
44935                }
44936            }else{
44937                // moved up/down
44938                scrollSection();
44939            }
44940        }
44941
44942        /*
44943        * Preventing bouncing in iOS #2285
44944        */
44945        function preventBouncing(event){
44946            var e = event.originalEvent;
44947            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){
44948                //preventing the easing on iOS devices
44949                event.preventDefault();
44950            }
44951        }
44952
44953        var touchStartY = 0;
44954        var touchStartX = 0;
44955        var touchEndY = 0;
44956        var touchEndX = 0;
44957
44958        /* Detecting touch events
44959
44960        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
44961        * This way, the touchstart and the touch moves shows an small difference between them which is the
44962        * used one to determine the direction.
44963        */
44964        function touchMoveHandler(event){
44965            var e = event.originalEvent;
44966            var activeSection = $(e.target).closest(SECTION_SEL);
44967
44968            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
44969            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
44970
44971                if(options.autoScrolling){
44972                    //preventing the easing on iOS devices
44973                    event.preventDefault();
44974                }
44975
44976                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
44977                var touchEvents = getEventsPage(e);
44978
44979                touchEndY = touchEvents.y;
44980                touchEndX = touchEvents.x;
44981
44982                //if movement in the X axys is greater than in the Y and the currect section has slides...
44983                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
44984
44985                    //is the movement greater than the minimum resistance to scroll?
44986                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
44987                        if (touchStartX > touchEndX) {
44988                            if(isScrollAllowed.m.right){
44989                                moveSlideRight(activeSection); //next
44990                            }
44991                        } else {
44992                            if(isScrollAllowed.m.left){
44993                                moveSlideLeft(activeSection); //prev
44994                            }
44995                        }
44996                    }
44997                }
44998
44999                //vertical scrolling (only when autoScrolling is enabled)
45000                else if(options.autoScrolling && canScroll){
45001
45002                    //is the movement greater than the minimum resistance to scroll?
45003                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
45004                        if (touchStartY > touchEndY) {
45005                            scrolling('down', scrollable);
45006                        } else if (touchEndY > touchStartY) {
45007                            scrolling('up', scrollable);
45008                        }
45009                    }
45010                }
45011            }
45012        }
45013
45014        /**
45015         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
45016         * Currently works well for iOS - Android might need some testing
45017         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
45018         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
45019         * @return {boolean} true if there is a match to options.normalScrollElements
45020         */
45021        function checkParentForNormalScrollElement (el, hop) {
45022            hop = hop || 0;
45023            var parent = $(el).parent();
45024
45025            if (hop < options.normalScrollElementTouchThreshold &&
45026                parent.is(options.normalScrollElements) ) {
45027                return true;
45028            } else if (hop == options.normalScrollElementTouchThreshold) {
45029                return false;
45030            } else {
45031                return checkParentForNormalScrollElement(parent, ++hop);
45032            }
45033        }
45034
45035        /**
45036        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
45037        * this way we make sure that is really a touch event what IE is detecting.
45038        */
45039        function isReallyTouch(e){
45040            //if is not IE   ||  IE is detecting `touch` or `pen`
45041            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
45042        }
45043
45044        /**
45045        * Handler for the touch start event.
45046        */
45047        function touchStartHandler(event){
45048            var e = event.originalEvent;
45049
45050            //stopping the auto scroll to adjust to a section
45051            if(options.fitToSection){
45052                $htmlBody.stop();
45053            }
45054
45055            if(isReallyTouch(e)){
45056                var touchEvents = getEventsPage(e);
45057                touchStartY = touchEvents.y;
45058                touchStartX = touchEvents.x;
45059            }
45060        }
45061
45062        /**
45063        * Gets the average of the last `number` elements of the given array.
45064        */
45065        function getAverage(elements, number){
45066            var sum = 0;
45067
45068            //taking `number` elements from the end to make the average, if there are not enought, 1
45069            var lastElements = elements.slice(Math.max(elements.length - number, 1));
45070
45071            for(var i = 0; i < lastElements.length; i++){
45072                sum = sum + lastElements[i];
45073            }
45074
45075            return Math.ceil(sum/number);
45076        }
45077
45078        /**
45079         * Detecting mousewheel scrolling
45080         *
45081         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
45082         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
45083         */
45084        var prevTime = new Date().getTime();
45085
45086        function MouseWheelHandler(e) {
45087            var curTime = new Date().getTime();
45088            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
45089
45090            //autoscrolling and not zooming?
45091            if(options.autoScrolling && !controlPressed && !isNormalScroll){
45092                // cross-browser wheel delta
45093                e = e || window.event;
45094                var value = e.wheelDelta || -e.deltaY || -e.detail;
45095                var delta = Math.max(-1, Math.min(1, value));
45096
45097                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
45098                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
45099
45100                //Limiting the array to 150 (lets not waste memory!)
45101                if(scrollings.length > 149){
45102                    scrollings.shift();
45103                }
45104
45105                //keeping record of the previous scrollings
45106                scrollings.push(Math.abs(value));
45107
45108                //preventing to scroll the site on mouse wheel when scrollbar is present
45109                if(options.scrollBar){
45110                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
45111                }
45112
45113                var activeSection = $(SECTION_ACTIVE_SEL);
45114                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
45115
45116                //time difference between the last scroll and the current one
45117                var timeDiff = curTime-prevTime;
45118                prevTime = curTime;
45119
45120                //haven't they scrolled in a while?
45121                //(enough to be consider a different scrolling action to scroll another section)
45122                if(timeDiff > 200){
45123                    //emptying the array, we dont care about old scrollings for our averages
45124                    scrollings = [];
45125                }
45126
45127                if(canScroll){
45128                    var averageEnd = getAverage(scrollings, 10);
45129                    var averageMiddle = getAverage(scrollings, 70);
45130                    var isAccelerating = averageEnd >= averageMiddle;
45131
45132                    //to avoid double swipes...
45133                    if(isAccelerating && isScrollingVertically){
45134                        //scrolling down?
45135                        if (delta < 0) {
45136                            scrolling('down', scrollable);
45137
45138                        //scrolling up?
45139                        }else {
45140                            scrolling('up', scrollable);
45141                        }
45142                    }
45143                }
45144
45145                return false;
45146            }
45147
45148            if(options.fitToSection){
45149                //stopping the auto scroll to adjust to a section
45150                $htmlBody.stop();
45151            }
45152        }
45153
45154        /**
45155        * Slides a slider to the given direction.
45156        * Optional `section` param.
45157        */
45158        function moveSlide(direction, section){
45159            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
45160            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
45161            var numSlides = slides.find(SLIDE_SEL).length;
45162
45163            // more than one slide needed and nothing should be sliding
45164            if (!slides.length || slideMoving || numSlides < 2) {
45165                return;
45166            }
45167
45168            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
45169            var destiny = null;
45170
45171            if(direction === 'left'){
45172                destiny = currentSlide.prev(SLIDE_SEL);
45173            }else{
45174                destiny = currentSlide.next(SLIDE_SEL);
45175            }
45176
45177            //isn't there a next slide in the secuence?
45178            if(!destiny.length){
45179                //respect loopHorizontal settin
45180                if (!options.loopHorizontal) return;
45181
45182                if(direction === 'left'){
45183                    destiny = currentSlide.siblings(':last');
45184                }else{
45185                    destiny = currentSlide.siblings(':first');
45186                }
45187            }
45188
45189            slideMoving = true;
45190
45191            landscapeScroll(slides, destiny, direction);
45192        }
45193
45194        /**
45195        * Maintains the active slides in the viewport
45196        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
45197        */
45198        function keepSlidesPosition(){
45199            $(SLIDE_ACTIVE_SEL).each(function(){
45200                silentLandscapeScroll($(this), 'internal');
45201            });
45202        }
45203
45204        var previousDestTop = 0;
45205        /**
45206        * Returns the destination Y position based on the scrolling direction and
45207        * the height of the section.
45208        */
45209        function getDestinationPosition(element){
45210            var elemPosition = element.position();
45211
45212            //top of the desination will be at the top of the viewport
45213            var position = elemPosition.top;
45214            var isScrollingDown =  elemPosition.top > previousDestTop;
45215            var sectionBottom = position - windowsHeight + element.outerHeight();
45216            var bigSectionsDestination = options.bigSectionsDestination;
45217
45218            //Uncode addition
45219            var containerH = container.outerHeight();
45220            var containerPosition = container.offset();
45221
45222            //########### Commented by Uncode - START ###########
45223            //is the destination element bigger than the viewport?
45224            // if(element.outerHeight() > windowsHeight){
45225            //     //scrolling up?
45226            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
45227            //         position = sectionBottom;
45228            //     }
45229            // }
45230
45231            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
45232            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
45233            //     //The bottom of the destination will be at the bottom of the viewport
45234            //     position = sectionBottom;
45235            // }
45236            //########### Commented by Uncode - END ###########
45237
45238            //Uncode addition
45239            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
45240                position += 18;
45241            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
45242                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
45243            }
45244
45245            /*
45246            Keeping record of the last scrolled position to determine the scrolling direction.
45247            No conventional methods can be used as the scroll bar might not be present
45248            AND the section might not be active if it is auto-height and didnt reach the middle
45249            of the viewport.
45250            */
45251            previousDestTop = position;
45252            return position;
45253        }
45254
45255        /**
45256        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
45257        */
45258        function scrollPage(element, callback, isMovementUp){
45259            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
45260
45261            var dtop = getDestinationPosition(element);
45262            var slideAnchorLink;
45263            var slideIndex;
45264
45265            //local variables
45266            var v = {
45267                element: element,
45268                callback: callback,
45269                isMovementUp: isMovementUp,
45270                dtop: dtop,
45271                yMovement: getYmovement(element),
45272                anchorLink: element.data('anchor'),
45273                sectionIndex: element.index(SECTION_SEL),
45274                activeSlide: element.find(SLIDE_ACTIVE_SEL),
45275                activeSection: $(SECTION_ACTIVE_SEL),
45276                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
45277
45278                //caching the value of isResizing at the momment the function is called
45279                //because it will be checked later inside a setTimeout and the value might change
45280                localIsResizing: isResizing
45281            };
45282
45283            //quiting when destination scroll is the same as the current one
45284            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
45285
45286            if(v.activeSlide.length){
45287                slideAnchorLink = v.activeSlide.data('anchor');
45288                slideIndex = v.activeSlide.index();
45289            }
45290
45291            // If continuousVertical && we need to wrap around
45292            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
45293                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
45294                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
45295
45296                v = createInfiniteSections(v);
45297            }
45298
45299            //callback (onLeave) if the site is not just resizing and readjusting the slides
45300            if($.isFunction(options.onLeave) && !v.localIsResizing){
45301                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
45302                    return;
45303                }
45304            }
45305
45306            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
45307            if(!v.localIsResizing){
45308                stopMedia(v.activeSection);
45309            }
45310
45311            options.scrollOverflowHandler.beforeLeave();
45312            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
45313            lazyLoad(element);
45314            options.scrollOverflowHandler.onLeave();
45315
45316
45317            //preventing from activating the MouseWheelHandler event
45318            //more than once if the page is scrolling
45319            canScroll = false;
45320
45321            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
45322
45323            performMovement(v);
45324
45325            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
45326            lastScrolledDestiny = v.anchorLink;
45327
45328            //avoid firing it twice (as it does also on scroll)
45329            activateMenuAndNav(v.anchorLink, v.sectionIndex);
45330        }
45331
45332        /**
45333        * Performs the vertical movement (by CSS3 or by jQuery)
45334        */
45335        function performMovement(v){
45336            // using CSS3 translate functionality
45337            if (options.css3 && options.autoScrolling && !options.scrollBar) {
45338
45339                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
45340                // that's why we round it to 0.
45341                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
45342                transformContainer(translate3d, true);
45343
45344                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
45345                //scrollingSpeed to change in case of using silentMoveTo();
45346                if(options.scrollingSpeed){
45347                    clearTimeout(afterSectionLoadsId);
45348                    afterSectionLoadsId = setTimeout(function () {
45349                        afterSectionLoads(v);
45350                    }, options.scrollingSpeed);
45351                }else{
45352                    afterSectionLoads(v);
45353                }
45354            }
45355
45356            // using jQuery animate
45357            else{
45358                var scrollSettings = getScrollSettings(v);
45359
45360                $(scrollSettings.element).animate(
45361                    scrollSettings.options,
45362                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
45363                    if(options.scrollBar){
45364
45365                        /* Hack!
45366                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
45367                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
45368
45369                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
45370                        */
45371                        setTimeout(function(){
45372                            afterSectionLoads(v);
45373                        },30);
45374                    }else{
45375                        afterSectionLoads(v);
45376                    }
45377                });
45378            }
45379        }
45380
45381        /**
45382        * Gets the scrolling settings depending on the plugin autoScrolling option
45383        */
45384        function getScrollSettings(v){
45385            var scroll = {};
45386
45387            if(options.autoScrolling && !options.scrollBar){
45388                scroll.options = { 'top': -v.dtop};
45389                scroll.element = WRAPPER_SEL;
45390            }else{
45391                scroll.options = { 'scrollTop': v.dtop};
45392                scroll.element = 'html, body';
45393            }
45394
45395            return scroll;
45396        }
45397
45398        /**
45399        * Adds sections before or after the current one to create the infinite effect.
45400        */
45401        function createInfiniteSections(v){
45402            // Scrolling down
45403            if (!v.isMovementUp) {
45404                // Move all previous sections to after the active section
45405                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
45406            }
45407            else { // Scrolling up
45408                // Move all next sections to before the active section
45409                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
45410            }
45411
45412            // Maintain the displayed position (now that we changed the element order)
45413            silentScroll($(SECTION_ACTIVE_SEL).position().top);
45414
45415            // Maintain the active slides visible in the viewport
45416            keepSlidesPosition();
45417
45418            // save for later the elements that still need to be reordered
45419            v.wrapAroundElements = v.activeSection;
45420
45421            // Recalculate animation variables
45422            v.dtop = v.element.position().top;
45423            v.yMovement = getYmovement(v.element);
45424
45425            return v;
45426        }
45427
45428        /**
45429        * Fix section order after continuousVertical changes have been animated
45430        */
45431        function continuousVerticalFixSectionOrder (v) {
45432            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
45433            // finish moving the elements around so the direct navigation will function more simply
45434            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
45435                return;
45436            }
45437
45438            if (v.isMovementUp) {
45439                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
45440            }
45441            else {
45442                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
45443            }
45444
45445            silentScroll($(SECTION_ACTIVE_SEL).position().top);
45446
45447            // Maintain the active slides visible in the viewport
45448            keepSlidesPosition();
45449        }
45450
45451
45452        /**
45453        * Actions to do once the section is loaded.
45454        */
45455        function afterSectionLoads (v){
45456            continuousVerticalFixSectionOrder(v);
45457
45458            //callback (afterLoad) if the site is not just resizing and readjusting the slides
45459            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
45460            options.scrollOverflowHandler.afterLoad();
45461
45462            if(!v.localIsResizing){
45463                playMedia(v.element);
45464            }
45465
45466            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
45467
45468            canScroll = true;
45469
45470            $.isFunction(v.callback) && v.callback.call(this);
45471        }
45472
45473        /**
45474        * Sets the value for the given attribute from the `data-` attribute with the same suffix
45475        * ie: data-srcset ==> srcset  |  data-src ==> src
45476        */
45477        function setSrc(element, attribute){
45478            element
45479                .attr(attribute, element.data(attribute))
45480                .removeAttr('data-' + attribute);
45481        }
45482
45483        /**
45484        * Lazy loads image, video and audio elements.
45485        */
45486        function lazyLoad(destiny){
45487            if (!options.lazyLoading){
45488                return;
45489            }
45490
45491            var panel = getSlideOrSection(destiny);
45492            var element;
45493
45494            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
45495                element = $(this);
45496
45497                $.each(['src', 'srcset'], function(index, type){
45498                    var attribute = element.attr('data-' + type);
45499                    if(typeof attribute !== 'undefined' && attribute){
45500                        setSrc(element, type);
45501                    }
45502                });
45503
45504                if(element.is('source')){
45505                    element.closest('video').get(0).load();
45506                }
45507            });
45508        }
45509
45510        /**
45511        * Plays video and audio elements.
45512        */
45513        function playMedia(destiny){
45514            var panel = getSlideOrSection(destiny);
45515
45516            //playing HTML5 media elements
45517            panel.find('video, audio').each(function(){
45518                var element = $(this).get(0);
45519
45520                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
45521                    element.play();
45522                }
45523            });
45524
45525            //youtube videos
45526            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
45527                var element = $(this).get(0);
45528
45529                if ( element.hasAttribute('data-autoplay') ){
45530                    playYoutube(element);
45531                }
45532
45533                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
45534                element.onload = function() {
45535                    if ( element.hasAttribute('data-autoplay') ){
45536                        playYoutube(element);
45537                    }
45538                };
45539            });
45540        }
45541
45542        /**
45543        * Plays a youtube video
45544        */
45545        function playYoutube(element){
45546            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
45547        }
45548
45549        /**
45550        * Stops video and audio elements.
45551        */
45552        function stopMedia(destiny){
45553            var panel = getSlideOrSection(destiny);
45554
45555            //stopping HTML5 media elements
45556            panel.find('video, audio').each(function(){
45557                var element = $(this).get(0);
45558
45559                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
45560                    element.pause();
45561                }
45562            });
45563
45564            //youtube videos
45565            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
45566                var element = $(this).get(0);
45567
45568                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
45569                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
45570                }
45571            });
45572        }
45573
45574        /**
45575        * Gets the active slide (or section) for the given section
45576        */
45577        function getSlideOrSection(destiny){
45578            var slide = destiny.find(SLIDE_ACTIVE_SEL);
45579            if( slide.length ) {
45580                destiny = $(slide);
45581            }
45582
45583            return destiny;
45584        }
45585
45586        /**
45587        * Scrolls to the anchor in the URL when loading the site
45588        */
45589        function scrollToAnchor(){
45590            //getting the anchor link in the URL and deleting the `#`
45591            var value =  window.location.hash.replace('#', '').split('/');
45592            var sectionAnchor = decodeURIComponent(value[0]);
45593            var slideAnchor = decodeURIComponent(value[1]);
45594
45595            if(sectionAnchor){  //if theres any #
45596                if(options.animateAnchor){
45597                    scrollPageAndSlide(sectionAnchor, slideAnchor);
45598                }else{
45599                    silentMoveTo(sectionAnchor, slideAnchor);
45600                }
45601            }
45602        }
45603
45604        /**
45605        * Detecting any change on the URL to scroll to the given anchor link
45606        * (a way to detect back history button as we play with the hashes on the URL)
45607        */
45608        function hashChangeHandler(){
45609            if(!isScrolling && !options.lockAnchors){
45610                var value =  window.location.hash.replace('#', '').split('/');
45611                var sectionAnchor = decodeURIComponent(value[0]);
45612                var slideAnchor = decodeURIComponent(value[1]);
45613
45614                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
45615                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
45616                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
45617
45618
45619                if(sectionAnchor.length){
45620                    /*in order to call scrollpage() only once for each destination at a time
45621                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
45622                    event is fired on every scroll too.*/
45623                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
45624                        scrollPageAndSlide(sectionAnchor, slideAnchor);
45625                    }
45626                }
45627            }
45628        }
45629
45630        //Sliding with arrow keys, both, vertical and horizontal
45631        function keydownHandler(e) {
45632
45633            clearTimeout(keydownId);
45634
45635            var activeElement = $(':focus');
45636
45637            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
45638                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
45639                options.keyboardScrolling && options.autoScrolling){
45640                var keyCode = e.which;
45641
45642                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
45643                var keyControls = [40, 38, 32, 33, 34];
45644                if($.inArray(keyCode, keyControls) > -1){
45645                    e.preventDefault();
45646                }
45647
45648                controlPressed = e.ctrlKey;
45649
45650                keydownId = setTimeout(function(){
45651                    onkeydown(e);
45652                },150);
45653            }
45654        }
45655
45656        function tooltipTextHandler(){
45657            $(this).prev().trigger('click');
45658        }
45659
45660        //to prevent scrolling while zooming
45661        function keyUpHandler(e){
45662            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
45663                controlPressed = e.ctrlKey;
45664            }
45665        }
45666
45667        //binding the mousemove when the mouse's middle button is released
45668        function mouseDownHandler(e){
45669            //middle button
45670            if (e.which == 2){
45671                oldPageY = e.pageY;
45672                container.on('mousemove', mouseMoveHandler);
45673            }
45674        }
45675
45676        //unbinding the mousemove when the mouse's middle button is released
45677        function mouseUpHandler(e){
45678            //middle button
45679            if (e.which == 2){
45680                container.off('mousemove');
45681            }
45682        }
45683
45684        //Scrolling horizontally when clicking on the slider controls.
45685        function slideArrowHandler(){
45686            var section = $(this).closest(SECTION_SEL);
45687
45688            if ($(this).hasClass(SLIDES_PREV)) {
45689                if(isScrollAllowed.m.left){
45690                    moveSlideLeft(section);
45691                }
45692            } else {
45693                if(isScrollAllowed.m.right){
45694                    moveSlideRight(section);
45695                }
45696            }
45697        }
45698
45699        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
45700        function blurHandler(){
45701            isWindowFocused = false;
45702            controlPressed = false;
45703        }
45704
45705        //Scrolls to the section when clicking the navigation bullet
45706        function sectionBulletHandler(e){
45707            e.preventDefault();
45708            var index = $(this).parent().index();
45709            scrollPage($(SECTION_SEL).eq(index));
45710        }
45711
45712        //Scrolls the slider to the given slide destination for the given section
45713        function slideBulletHandler(e){
45714            e.preventDefault();
45715            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
45716            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
45717
45718            landscapeScroll(slides, destiny);
45719        }
45720
45721        /**
45722        * Keydown event
45723        */
45724        function onkeydown(e){
45725            var shiftPressed = e.shiftKey;
45726
45727            //do nothing if we can not scroll or we are not using horizotnal key arrows.
45728            if(!canScroll && [37,39].indexOf(e.which) < 0){
45729                return;
45730            }
45731
45732            switch (e.which) {
45733                //up
45734                case 38:
45735                case 33:
45736                    if(isScrollAllowed.k.up){
45737                        moveSectionUp();
45738                    }
45739                    break;
45740
45741                //down
45742                case 32: //spacebar
45743                    if(shiftPressed && isScrollAllowed.k.up){
45744                        moveSectionUp();
45745                        break;
45746                    }
45747                /* falls through */
45748                case 40:
45749                case 34:
45750                    if(isScrollAllowed.k.down){
45751                        moveSectionDown();
45752                    }
45753                    break;
45754
45755                //Home
45756                case 36:
45757                    if(isScrollAllowed.k.up){
45758                        moveTo(1);
45759                    }
45760                    break;
45761
45762                //End
45763                case 35:
45764                     if(isScrollAllowed.k.down){
45765                        moveTo( $(SECTION_SEL).length );
45766                    }
45767                    break;
45768
45769                //left
45770                case 37:
45771                    if(isScrollAllowed.k.left){
45772                        moveSlideLeft();
45773                    }
45774                    break;
45775
45776                //right
45777                case 39:
45778                    if(isScrollAllowed.k.right){
45779                        moveSlideRight();
45780                    }
45781                    break;
45782
45783                default:
45784                    return; // exit this handler for other keys
45785            }
45786        }
45787
45788        /**
45789        * Detecting the direction of the mouse movement.
45790        * Used only for the middle button of the mouse.
45791        */
45792        var oldPageY = 0;
45793        function mouseMoveHandler(e){
45794            if(canScroll){
45795                // moving up
45796                if (e.pageY < oldPageY && isScrollAllowed.m.up){
45797                    moveSectionUp();
45798                }
45799
45800                // moving down
45801                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
45802                    moveSectionDown();
45803                }
45804            }
45805            oldPageY = e.pageY;
45806        }
45807
45808        /**
45809        * Scrolls horizontal sliders.
45810        */
45811        function landscapeScroll(slides, destiny, direction){
45812            var section = slides.closest(SECTION_SEL);
45813            var v = {
45814                slides: slides,
45815                destiny: destiny,
45816                direction: direction,
45817                destinyPos: destiny.position(),
45818                slideIndex: destiny.index(),
45819                section: section,
45820                sectionIndex: section.index(SECTION_SEL),
45821                anchorLink: section.data('anchor'),
45822                slidesNav: section.find(SLIDES_NAV_SEL),
45823                slideAnchor:  getAnchor(destiny),
45824                prevSlide: section.find(SLIDE_ACTIVE_SEL),
45825                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
45826
45827                //caching the value of isResizing at the momment the function is called
45828                //because it will be checked later inside a setTimeout and the value might change
45829                localIsResizing: isResizing
45830            };
45831            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
45832            v.direction = v.direction ? v.direction : v.xMovement;
45833
45834            //important!! Only do it when not resizing
45835            if(!v.localIsResizing){
45836                //preventing from scrolling to the next/prev section when using scrollHorizontally
45837                canScroll = false;
45838            }
45839
45840            if(options.onSlideLeave){
45841
45842                //if the site is not just resizing and readjusting the slides
45843                if(!v.localIsResizing && v.xMovement!=='none'){
45844                    if($.isFunction( options.onSlideLeave )){
45845                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
45846                            slideMoving = false;
45847                            return;
45848                        }
45849                    }
45850                }
45851            }
45852
45853            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
45854
45855            if(!v.localIsResizing){
45856                stopMedia(v.prevSlide);
45857                lazyLoad(destiny);
45858            }
45859
45860            if(!options.loopHorizontal && options.controlArrows){
45861                //hidding it for the fist slide, showing for the rest
45862                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
45863
45864                //hidding it for the last slide, showing for the rest
45865                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
45866            }
45867
45868            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
45869            if(section.hasClass(ACTIVE) && !v.localIsResizing){
45870                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
45871            }
45872
45873            performHorizontalMove(slides, v, true);
45874        }
45875
45876
45877        function afterSlideLoads(v){
45878            activeSlidesNavigation(v.slidesNav, v.slideIndex);
45879
45880            //if the site is not just resizing and readjusting the slides
45881            if(!v.localIsResizing){
45882                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
45883
45884                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
45885                //and to prevent double scroll right after a windows resize
45886                canScroll = true;
45887
45888                playMedia(v.destiny);
45889            }
45890
45891            //letting them slide again
45892            slideMoving = false;
45893        }
45894
45895        /**
45896        * Performs the horizontal movement. (CSS3 or jQuery)
45897        *
45898        * @param fireCallback {Bool} - determines whether or not to fire the callback
45899        */
45900        function performHorizontalMove(slides, v, fireCallback){
45901            var destinyPos = v.destinyPos;
45902
45903            if(options.css3){
45904                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
45905
45906                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
45907
45908                afterSlideLoadsId = setTimeout(function(){
45909                    fireCallback && afterSlideLoads(v);
45910                }, options.scrollingSpeed, options.easing);
45911            }else{
45912                slides.animate({
45913                    scrollLeft : Math.round(destinyPos.left)
45914                }, options.scrollingSpeed, options.easing, function() {
45915
45916                    fireCallback && afterSlideLoads(v);
45917                });
45918            }
45919        }
45920
45921        /**
45922        * Sets the state for the horizontal bullet navigations.
45923        */
45924        function activeSlidesNavigation(slidesNav, slideIndex){
45925            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
45926            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
45927        }
45928
45929        var previousHeight = windowsHeight;
45930
45931        //when resizing the site, we adjust the heights of the sections, slimScroll...
45932        function resizeHandler(){
45933            //checking if it needs to get responsive
45934            responsive();
45935
45936            // rebuild immediately on touch devices
45937            if (isTouchDevice) {
45938                var activeElement = $(document.activeElement);
45939
45940                //if the keyboard is NOT visible
45941                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
45942                    var currentHeight = $window.height();
45943
45944                    //making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars)
45945                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
45946                        reBuild(true);
45947                        previousHeight = currentHeight;
45948                    }
45949                }
45950            }else{
45951                //in order to call the functions only when the resize is finished
45952                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
45953                clearTimeout(resizeId);
45954
45955                resizeId = setTimeout(function(){
45956                    reBuild(true);
45957                }, 350);
45958            }
45959        }
45960
45961        /**
45962        * Checks if the site needs to get responsive and disables autoScrolling if so.
45963        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
45964        */
45965        function responsive(){
45966            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
45967            var heightLimit = options.responsiveHeight;
45968
45969            //only calculating what we need. Remember its called on the resize event.
45970            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
45971            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
45972
45973            if(widthLimit && heightLimit){
45974                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
45975            }
45976            else if(widthLimit){
45977                setResponsive(isBreakingPointWidth);
45978            }
45979            else if(heightLimit){
45980                setResponsive(isBreakingPointHeight);
45981            }
45982        }
45983
45984        /**
45985        * Adds transition animations for the given element
45986        */
45987        function addAnimation(container, element){
45988            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
45989
45990            container.removeClass(NO_TRANSITION);
45991            return container.css({
45992                '-webkit-transition': transition,
45993                'transition': transition
45994            });
45995        }
45996
45997        /**
45998        * Remove transition animations for the given element
45999        */
46000        function removeAnimation(element){
46001            return element.addClass(NO_TRANSITION);
46002        }
46003
46004        /**
46005        * Activating the vertical navigation bullets according to the given slide name.
46006        */
46007        function activateNavDots(name, sectionIndex){
46008            if(options.navigation){
46009                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
46010                if(name){
46011                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
46012                }else{
46013                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
46014                }
46015            }
46016        }
46017
46018        /**
46019        * Activating the website main menu elements according to the given slide name.
46020        */
46021        function activateMenuElement(name){
46022            if(options.menu){
46023                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
46024                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
46025            }
46026        }
46027
46028        /**
46029        * Sets to active the current menu and vertical nav items.
46030        */
46031        function activateMenuAndNav(anchor, index){
46032            activateMenuElement(anchor);
46033            activateNavDots(anchor, index);
46034        }
46035
46036        /**
46037        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
46038        * from the current section.
46039        */
46040        function getYmovement(destiny){
46041            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
46042            var toIndex = destiny.index(SECTION_SEL);
46043            if( fromIndex == toIndex){
46044                return 'none';
46045            }
46046            if(fromIndex > toIndex){
46047                return 'up';
46048            }
46049            return 'down';
46050        }
46051
46052        /**
46053        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
46054        * from the current slide.
46055        */
46056        function getXmovement(fromIndex, toIndex){
46057            if( fromIndex == toIndex){
46058                return 'none';
46059            }
46060            if(fromIndex > toIndex){
46061                return 'left';
46062            }
46063            return 'right';
46064        }
46065
46066        /**
46067        * Checks if the element needs scrollbar and if the user wants to apply it.
46068        * If so it creates it.
46069        *
46070        * @param {Object} element   jQuery object of the section or slide
46071        */
46072        function createScrollBar(element){
46073            //User doesn't want scrollbar here? Sayonara baby!
46074            if(element.hasClass('fp-noscroll')) return;
46075
46076            //needed to make `scrollHeight` work under Opera 12
46077            element.css('overflow', 'hidden');
46078
46079            var scrollOverflowHandler = options.scrollOverflowHandler;
46080            var wrap = scrollOverflowHandler.wrapContent();
46081            //in case element is a slide
46082            var section = element.closest(SECTION_SEL);
46083            var scrollable = scrollOverflowHandler.scrollable(element);
46084            var contentHeight;
46085
46086            //if there was scroll, the contentHeight will be the one in the scrollable section
46087            if(scrollable.length){
46088                contentHeight = scrollOverflowHandler.scrollHeight(element);
46089            }else{
46090                contentHeight = element.get(0).scrollHeight;
46091                if(options.verticalCentered){
46092                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
46093                }
46094            }
46095
46096            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
46097
46098            //needs scroll?
46099            if ( contentHeight > scrollHeight) {
46100                //did we already have an scrollbar ? Updating it
46101                if(scrollable.length){
46102                    scrollOverflowHandler.update(element, scrollHeight);
46103                }
46104                //creating the scrolling
46105                else{
46106                    if(options.verticalCentered){
46107                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
46108                    }else{
46109                        element.wrapInner(wrap);
46110                    }
46111                    scrollOverflowHandler.create(element, scrollHeight);
46112                }
46113            }
46114            //removing the scrolling when it is not necessary anymore
46115            else{
46116                scrollOverflowHandler.remove(element);
46117            }
46118
46119            //undo
46120            element.css('overflow', '');
46121        }
46122
46123        function addTableClass(element){
46124            //In case we are styling for the 2nd time as in with reponsiveSlides
46125            if(!element.hasClass(TABLE)){
46126                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
46127            }
46128        }
46129
46130        function getTableHeight(element){
46131            var sectionHeight = windowsHeight;
46132
46133            if(options.paddingTop || options.paddingBottom){
46134                var section = element;
46135                if(!section.hasClass(SECTION)){
46136                    section = element.closest(SECTION_SEL);
46137                }
46138
46139                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
46140                sectionHeight = (windowsHeight - paddings);
46141            }
46142
46143            return sectionHeight;
46144        }
46145
46146        /**
46147        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
46148        */
46149        function transformContainer(translate3d, animated){
46150            if(animated){
46151                addAnimation(container);
46152            }else{
46153                removeAnimation(container);
46154            }
46155
46156            container.css(getTransforms(translate3d));
46157
46158            //syncronously removing the class after the animation has been applied.
46159            setTimeout(function(){
46160                container.removeClass(NO_TRANSITION);
46161            },10);
46162        }
46163
46164        /**
46165        * Gets a section by its anchor / index
46166        */
46167        function getSectionByAnchor(sectionAnchor){
46168            if(!sectionAnchor) return [];
46169
46170            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
46171            if(!section.length){
46172                section = $(SECTION_SEL).eq( sectionAnchor -1);
46173            }
46174
46175            return section;
46176        }
46177
46178        /**
46179        * Gets a slide inside a given section by its anchor / index
46180        */
46181        function getSlideByAnchor(slideAnchor, section){
46182            var slides = section.find(SLIDES_WRAPPER_SEL);
46183            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
46184
46185            if(!slide.length){
46186                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
46187            }
46188
46189            return slide;
46190        }
46191
46192        /**
46193        * Scrolls to the given section and slide anchors
46194        */
46195        function scrollPageAndSlide(destiny, slide){
46196            var section = getSectionByAnchor(destiny);
46197
46198            //do nothing if there's no section with the given anchor name
46199            if(!section.length) return;
46200
46201            //default slide
46202            if (typeof slide === 'undefined') {
46203                slide = 0;
46204            }
46205
46206            //we need to scroll to the section and then to the slide
46207            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
46208                scrollPage(section, function(){
46209                    scrollSlider(section, slide);
46210                });
46211            }
46212            //if we were already in the section
46213            else{
46214                scrollSlider(section, slide);
46215            }
46216        }
46217
46218        /**
46219        * Scrolls the slider to the given slide destination for the given section
46220        */
46221        function scrollSlider(section, slideAnchor){
46222            if(typeof slideAnchor !== 'undefined'){
46223                var slides = section.find(SLIDES_WRAPPER_SEL);
46224                var destiny =  getSlideByAnchor(slideAnchor, section);
46225
46226                if(destiny.length){
46227                    landscapeScroll(slides, destiny);
46228                }
46229            }
46230        }
46231
46232        /**
46233        * Creates a landscape navigation bar with dots for horizontal sliders.
46234        */
46235        function addSlidesNavigation(section, numSlides){
46236            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
46237            var nav = section.find(SLIDES_NAV_SEL);
46238
46239            //top or bottom
46240            nav.addClass(options.slidesNavPosition);
46241
46242            for(var i=0; i< numSlides; i++){
46243                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
46244            }
46245
46246            //centering it
46247            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
46248
46249            nav.find('li').first().find('a').addClass(ACTIVE);
46250        }
46251
46252
46253        /**
46254        * Sets the state of the website depending on the active section/slide.
46255        * It changes the URL hash when needed and updates the body class.
46256        */
46257        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
46258            var sectionHash = '';
46259
46260            if(options.anchors.length && !options.lockAnchors){
46261
46262                //isn't it the first slide?
46263                if(slideIndex){
46264                    if(typeof anchorLink !== 'undefined'){
46265                        sectionHash = anchorLink;
46266                    }
46267
46268                    //slide without anchor link? We take the index instead.
46269                    if(typeof slideAnchor === 'undefined'){
46270                        slideAnchor = slideIndex;
46271                    }
46272
46273                    lastScrolledSlide = slideAnchor;
46274                    setUrlHash(sectionHash + '/' + slideAnchor);
46275
46276                //first slide won't have slide anchor, just the section one
46277                }else if(typeof slideIndex !== 'undefined'){
46278                    lastScrolledSlide = slideAnchor;
46279                    setUrlHash(anchorLink);
46280                }
46281
46282                //section without slides
46283                else{
46284                    setUrlHash(anchorLink);
46285                }
46286            }
46287
46288            setBodyClass();
46289        }
46290
46291        /**
46292        * Sets the URL hash.
46293        */
46294        function setUrlHash(url){
46295            //Uncode addition
46296            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
46297                return false;
46298
46299            if(options.recordHistory){
46300                location.hash = url;
46301            }else{
46302                //Uncode addition
46303                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
46304                // if(isTouchDevice || isTouch){
46305                //     window.history.replaceState(undefined, undefined, '#' + url);
46306                // }else{
46307                //     var baseUrl = window.location.href.split('#')[0];
46308                //     window.location.replace( baseUrl + '#' + url );
46309                // }
46310                return false;
46311            }
46312        }
46313
46314        /**
46315        * Gets the anchor for the given slide / section. Its index will be used if there's none.
46316        */
46317        function getAnchor(element){
46318            var anchor = element.data('anchor');
46319            var index = element.index();
46320
46321            //Slide without anchor link? We take the index instead.
46322            if(typeof anchor === 'undefined'){
46323                anchor = index;
46324            }
46325
46326            return anchor;
46327        }
46328
46329        /**
46330        * Sets a class for the body of the page depending on the active section / slide
46331        */
46332        function setBodyClass(){
46333            var section = $(SECTION_ACTIVE_SEL);
46334            var slide = section.find(SLIDE_ACTIVE_SEL);
46335
46336            var sectionAnchor = getAnchor(section);
46337            var slideAnchor = getAnchor(slide);
46338
46339            var text = String(sectionAnchor);
46340
46341            if(slide.length){
46342                text = text + '-' + slideAnchor;
46343            }
46344
46345            //changing slash for dash to make it a valid CSS style
46346            text = text.replace('/', '-').replace('#','');
46347
46348            //removing previous anchor classes
46349            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
46350            $body[0].className = $body[0].className.replace(classRe, '');
46351
46352            //adding the current anchor
46353            $body.addClass(VIEWING_PREFIX + '-' + text);
46354        }
46355
46356        /**
46357        * Checks for translate3d support
46358        * @return boolean
46359        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
46360        */
46361        function support3d() {
46362            var el = document.createElement('p'),
46363                has3d,
46364                transforms = {
46365                    'webkitTransform':'-webkit-transform',
46366                    'OTransform':'-o-transform',
46367                    'msTransform':'-ms-transform',
46368                    'MozTransform':'-moz-transform',
46369                    'transform':'transform'
46370                };
46371
46372            // Add it to the body to get the computed style.
46373            document.body.insertBefore(el, null);
46374
46375            for (var t in transforms) {
46376                if (el.style[t] !== undefined) {
46377                    el.style[t] = 'translate3d(1px,1px,1px)';
46378                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
46379                }
46380            }
46381
46382            document.body.removeChild(el);
46383
46384            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
46385        }
46386
46387        /**
46388        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
46389        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
46390        */
46391        function removeMouseWheelHandler(){
46392            if (document.addEventListener) {
46393                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
46394                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
46395                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
46396            } else {
46397                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
46398            }
46399        }
46400
46401        /**
46402        * Adds the auto scrolling action for the mouse wheel and trackpad.
46403        * After this function is called, the mousewheel and trackpad movements will scroll through sections
46404        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
46405        */
46406        function addMouseWheelHandler(){
46407            var prefix = '';
46408            var _addEventListener;
46409
46410            if (window.addEventListener){
46411                _addEventListener = "addEventListener";
46412            }else{
46413                _addEventListener = "attachEvent";
46414                prefix = 'on';
46415            }
46416
46417             // detect available wheel event
46418            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
46419                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
46420                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
46421            var passiveEvent = g_supportsPassive ? {passive: false }
46421: false;
46422
46423
46424            if(support == 'DOMMouseScroll'){
46425                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent);
46426            }
46427
46428            //handle MozMousePixelScroll in older Firefox
46429            else{
46430                document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent);
46431            }
46432        }
46433
46434        /**
46435        * Binding the mousemove when the mouse's middle button is pressed
46436        */
46437        function addMiddleWheelHandler(){
46438            container
46439                .on('mousedown', mouseDownHandler)
46440                .on('mouseup', mouseUpHandler);
46441        }
46442
46443        /**
46444        * Unbinding the mousemove when the mouse's middle button is released
46445        */
46446        function removeMiddleWheelHandler(){
46447            container
46448                .off('mousedown', mouseDownHandler)
46449                .off('mouseup', mouseUpHandler);
46450        }
46451
46452        /**
46453        * Adds the possibility to auto scroll through sections on touch devices.
46454        */
46455        function addTouchHandler(){
46456            if(isTouchDevice || isTouch){
46457                if(options.autoScrolling){
46458                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
46459                }
46460
46461                $(WRAPPER_SEL)
46462                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
46463                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
46464            }
46465        }
46466
46467        /**
46468        * Removes the auto scrolling for touch devices.
46469        */
46470        function removeTouchHandler(){
46471            if(isTouchDevice || isTouch){
46472                $(WRAPPER_SEL)
46473                    .off(events.touchstart)
46474                    .off(events.touchmove);
46475            }
46476        }
46477
46478        /*
46479        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
46480        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
46481        */
46482        function getMSPointer(){
46483            var pointer;
46484
46485            //IE >= 11 & rest of browsers
46486            if(window.PointerEvent){
46487                pointer = { down: 'pointerdown', move: 'pointermove'};
46488            }
46489
46490            //IE < 11
46491            else{
46492                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
46493            }
46494
46495            return pointer;
46496        }
46497
46498        /**
46499        * Gets the pageX and pageY properties depending on the browser.
46500        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
46501        */
46502        function getEventsPage(e){
46503            var events = [];
46504
46505            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
46506            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
46507
46508            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
46509            if(isTouch && isReallyTouch(e) && options.scrollBar){
46510                events.y = e.touches[0].pageY;
46511                events.x = e.touches[0].pageX;
46512            }
46513
46514            return events;
46515        }
46516
46517        /**
46518        * Slides silently (with no animation) the active slider to the given slide.
46519        * @param noCallback {bool} true or defined -> no callbacks
46520        */
46521        function silentLandscapeScroll(activeSlide, noCallbacks){
46522            setScrollingSpeed (0, 'internal');
46523
46524            if(typeof noCallbacks !== 'undefined'){
46525                //preventing firing callbacks afterSlideLoad etc.
46526                isResizing = true;
46527            }
46528
46529            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
46530
46531            if(typeof noCallbacks !== 'undefined'){
46532                isResizing = false;
46533            }
46534
46535            setScrollingSpeed(originals.scrollingSpeed, 'internal');
46536        }
46537
46538        /**
46539        * Scrolls silently (with no animation) the page to the given Y position.
46540        */
46541        function silentScroll(top){
46542            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
46543            // that's why we round it to 0.
46544            var roundedTop = Math.round(top);
46545
46546            if (options.css3 && options.autoScrolling && !options.scrollBar){
46547                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
46548                transformContainer(translate3d, false);
46549            }
46550            else if(options.autoScrolling && !options.scrollBar){
46551                container.css('top', -roundedTop);
46552            }
46553            else{
46554                $htmlBody.scrollTop(roundedTop);
46555            }
46556        }
46557
46558        /**
46559        * Returns the cross-browser transform string.
46560        */
46561        function getTransforms(translate3d){
46562            return {
46563                '-webkit-transform': translate3d,
46564                '-moz-transform': translate3d,
46565                '-ms-transform':translate3d,
46566                'transform': translate3d
46567            };
46568        }
46569
46570        /**
46571        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
46572        * @type  m (mouse) or k (keyboard)
46573        */
46574        function setIsScrollAllowed(value, direction, type){
46575            switch (direction){
46576                case 'up': isScrollAllowed[type].up = value; break;
46577                case 'down': isScrollAllowed[type].down = value; break;
46578                case 'left': isScrollAllowed[type].left = value; break;
46579                case 'right': isScrollAllowed[type].right = value; break;
46580                case 'all':
46581                    if(type == 'm'){
46582                        setAllowScrolling(value);
46583                    }else{
46584                        setKeyboardScrolling(value);
46585                    }
46586            }
46587        }
46588
46589        /*
46590        * Destroys fullpage.js plugin events and optinally its html markup and styles
46591        */
46592        function destroy(all){
46593            setAutoScrolling(false, 'internal');
46594            setAllowScrolling(false);
46595            setKeyboardScrolling(false);
46596            container.addClass(DESTROYED);
46597
46598            clearTimeout(afterSlideLoadsId);
46599            clearTimeout(afterSectionLoadsId);
46600            clearTimeout(resizeId);
46601            clearTimeout(scrollId);
46602            clearTimeout(scrollId2);
46603
46604            $window
46605                .off('scroll', scrollHandler)
46606                .off('hashchange', hashChangeHandler)
46607                .off('resize', resizeHandler);
46608
46609            $document
46610                .off('click touchstart', SECTION_NAV_SEL + ' a')
46611                .off('mouseenter', SECTION_NAV_SEL + ' li')
46612                .off('mouseleave', SECTION_NAV_SEL + ' li')
46613                .off('click touchstart', SLIDES_NAV_LINK_SEL)
46614                .off('mouseover', options.normalScrollElements)
46615                .off('mouseout', options.normalScrollElements);
46616
46617            $(SECTION_SEL)
46618                .off('click touchstart', SLIDES_ARROW_SEL);
46619
46620            clearTimeout(afterSlideLoadsId);
46621            clearTimeout(afterSectionLoadsId);
46622
46623            //lets make a mess!
46624            if(all){
46625                destroyStructure();
46626            }
46627        }
46628
46629        /*
46630        * Removes inline styles added by fullpage.js
46631        */
46632        function destroyStructure(){
46633            //reseting the `top` or `translate` properties to 0
46634            silentScroll(0);
46635
46636            //loading all the lazy load content
46637            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
46638                setSrc($(this), 'src');
46639            });
46640
46641            container.find('img[data-srcset]').each(function(){
46642                setSrc($(this), 'srcset');
46643            });
46644
46645            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
46646
46647            //removing inline styles
46648            $(SECTION_SEL).css( {
46649                'height': '',
46650                'background-color' : '',
46651                'padding': ''
46652            });
46653
46654            $(SLIDE_SEL).css( {
46655                'width': ''
46656            });
46657
46658            container.css({
46659                'height': '',
46660                'position': '',
46661                '-ms-touch-action': '',
46662                'touch-action': ''
46663            });
46664
46665            $htmlBody.css({
46666                'overflow': '',
46667                'height': ''
46668            });
46669
46670            // remove .fp-enabled class
46671            $('html').removeClass(ENABLED);
46672
46673            // remove .fp-responsive class
46674            $body.removeClass(RESPONSIVE);
46675
46676            // remove all of the .fp-viewing- classes
46677            $.each($body.get(0).className.split(/\s+/), function (index, className) {
46678                if (className.indexOf(VIEWING_PREFIX) === 0) {
46679                    $body.removeClass(className);
46680                }
46681            });
46682
46683            //removing added classes
46684            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
46685                options.scrollOverflowHandler.remove($(this));
46686                $(this).removeClass(TABLE + ' ' + ACTIVE);
46687            });
46688
46689            removeAnimation(container);
46690
46691            //Unwrapping content
46692            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
46693                //unwrap not being use in case there's no child element inside and its just text
46694                $(this).replaceWith(this.childNodes);
46695            });
46696
46697            //removing the applied transition from the fullpage wrapper
46698            container.css({
46699                '-webkit-transition': 'none',
46700                'transition': 'none'
46701            });
46702
46703            //scrolling the page to the top with no animation
46704            $htmlBody.scrollTop(0);
46705
46706            //removing selectors
46707            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
46708            $.each(usedSelectors, function(index, value){
46709                $('.' + value).removeClass(value);
46710            });
46711        }
46712
46713        /*
46714        * Sets the state for a variable with multiple states (original, and temporal)
46715        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
46716        * This function is used to keep track of both states, the original and the temporal one.
46717        * If type is not 'internal', then we assume the user is globally changing the variable.
46718        */
46719        function setVariableState(variable, value, type){
46720            options[variable] = value;
46721            if(type !== 'internal'){
46722                originals[variable] = value;
46723            }
46724        }
46725
46726        /**
46727        * Displays warnings
46728        */
46729        function displayWarnings(){
46730            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
46731            //UNCODE.addition
46732            // if($('html').hasClass(ENABLED)){
46733            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
46734            //     return;
46735            // }
46736
46737            // Disable mutually exclusive settings
46738            //UNCODE.addition
46739            // if (options.continuousVertical &&
46740            //     (options.loopTop || options.loopBottom)) {
46741            //     options.continuousVertical = false;
46742            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
46743            // }
46744
46745            // if(options.scrollBar && options.scrollOverflow){
46746            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
46747            // }
46748
46749            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
46750            //     options.continuousVertical = false;
46751            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
46752            // }
46753
46754            //using extensions? Wrong file!
46755            $.each(extensions, function(index, extension){
46756                //is the option set to true?
46757                if(options[extension]){
46758                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
46759                }
46760            });
46761
46762            //anchors can not have the same value as any element ID or NAME
46763            $.each(options.anchors, function(index, name){
46764
46765                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
46766                var nameAttr = $document.find('[name]').filter(function() {
46767                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
46768                });
46769
46770                var idAttr = $document.find('[id]').filter(function() {
46771                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
46772                });
46773
46774                if(idAttr.length || nameAttr.length ){
46775                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
46776                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
46777                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
46778                }
46779            });
46780        }
46781
46782        /**
46783        * Shows a message in the console of the given type.
46784        */
46785        function showError(type, text){
46786            console && console[type] && console[type]('fullPage: ' + text);
46787        }
46788
46789    }; //end of $.fn.fullpage
46790
46791    if(typeof IScroll !== 'undefined'){
46792        /*
46793        * Turns iScroll `mousewheel` option off dynamically
46794        * https://github.com/cubiq/iscroll/issues/1036
46795        */
46796        IScroll.prototype.wheelOn = function () {
46797            this.wrapper.addEventListener('wheel', this);
46798            this.wrapper.addEventListener('mousewheel', this);
46799            this.wrapper.addEventListener('DOMMouseScroll', this);
46800        };
46801
46802        /*
46803        * Turns iScroll `mousewheel` option on dynamically
46804        * https://github.com/cubiq/iscroll/issues/1036
46805        */
46806        IScroll.prototype.wheelOff = function () {
46807            this.wrapper.removeEventListener('wheel', this);
46808            this.wrapper.removeEventListener('mousewheel', this);
46809            this.wrapper.removeEventListener('DOMMouseScroll', this);
46810        };
46811    }
46812
46813    /**
46814     * An object to handle overflow scrolling.
46815     * This uses jquery.slimScroll to accomplish overflow scrolling.
46816     * It is possible to pass in an alternate scrollOverflowHandler
46817     * to the fullpage.js option that implements the same functions
46818     * as this handler.
46819     *
46820     * @type {Object}
46821     */
46822    var iscrollHandler = {
46823        refreshId: null,
46824        iScrollInstances: [],
46825
46826        // Enables or disables the mouse wheel for the active section or all slides in it
46827        toggleWheel: function(value){
46828            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
46829            scrollable.each(function(){
46830                var iScrollInstance = $(this).data('iscrollInstance');
46831                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
46832                    if(value){
46833                        iScrollInstance.wheelOn();
46834                    }
46835                    else{
46836                        iScrollInstance.wheelOff();
46837                    }
46838                }
46839            });
46840        },
46841
46842        /**
46843        * Turns off iScroll for the destination section.
46844        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
46845        * scroll the destination section/slide before the sections animations ends.
46846        */
46847        onLeave: function(){
46848            iscrollHandler.toggleWheel(false);
46849        },
46850
46851        // Turns off iScroll for the leaving section
46852        beforeLeave: function(){
46853            iscrollHandler.onLeave()
46854        },
46855
46856        // Turns on iScroll on section load
46857        afterLoad: function(){
46858            iscrollHandler.toggleWheel(true);
46859        },
46860
46861        /**
46862         * Called when overflow scrolling is needed for a section.
46863         *
46864         * @param  {Object} element      jQuery object containing current section
46865         * @param  {Number} scrollHeight Current window height in pixels
46866         */
46867        create: function(element, scrollHeight) {
46868            var scrollable = element.find(SCROLLABLE_SEL);
46869
46870            scrollable.height(scrollHeight);
46871            scrollable.each(function() {
46872                var $this = $(this);
46873                var iScrollInstance = $this.data('iscrollInstance');
46874                if (iScrollInstance) {
46875                    $.each(iscrollHandler.iScrollInstances, function(){
46876                        $(this).destroy();
46877                    });
46878                }
46879
46880                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
46881                iscrollHandler.iScrollInstances.push(iScrollInstance);
46882
46883                //off by default until the section gets active
46884                iScrollInstance.wheelOff();
46885
46886                $this.data('iscrollInstance', iScrollInstance);
46887            });
46888        },
46889
46890        /**
46891         * Return a boolean depending on whether the scrollable element is a
46892         * the end or at the start of the scrolling depending on the given type.
46893         *
46894         * @param  {String}  type       Either 'top' or 'bottom'
46895         * @param  {Object}  scrollable jQuery object for the scrollable element
46896         * @return {Boolean}
46897         */
46898        isScrolled: function(type, scrollable) {
46899            var scroller = scrollable.data('iscrollInstance');
46900
46901            //no scroller?
46902            if (!scroller) {
46903                return true;
46904            }
46905
46906            //Uncode addition
46907            var uncode_body_borders = parseFloat($('.body-borders').attr('data-border')) || 0;
46908            //End Uncode addition
46909
46910            if (type === 'top') {
46911                return scroller.y >= 0 && !scrollable.scrollTop();
46912            } else if (type === 'bottom') {
46913                //Uncode change
46914                // return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
46915                return (0 - scroller.y) + scrollable.scrollTop() + 1 + ( uncode_body_borders * 2 ) + scrollable.innerHeight() >= scrollable[0].scrollHeight;
46916                //End Uncode change
46917            }
46918        },
46919
46920        /**
46921         * Returns the scrollable element for the given section.
46922         * If there are landscape slides, will only return a scrollable element
46923         * if it is in the active slide.
46924         *
46925         * @param  {Object}  activeSection jQuery object containing current section
46926         * @return {Boolean}
46927         */
46928        scrollable: function(activeSection){
46929            // if there are landscape slides, we check if the scrolling bar is in the current one or not
46930            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
46931                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
46932            }
46933            return activeSection.find(SCROLLABLE_SEL);
46934        },
46935
46936        /**
46937         * Returns the scroll height of the wrapped content.
46938         * If this is larger than the window height minus section padding,
46939         * overflow scrolling is needed.
46940         *
46941         * @param  {Object} element jQuery object containing current section
46942         * @return {Number}
46943         */
46944        scrollHeight: function(element) {
46945            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
46946        },
46947
46948        /**
46949         * Called when overflow scrolling is no longer needed for a section.
46950         *
46951         * @param  {Object}
vendor: 5,435 bytes, lines 46951-47102
46951 element      jQuery object containing current section
46952         */
46953        remove: function(element) {
46954            var scrollable = element.find(SCROLLABLE_SEL);
46955            if (scrollable.length) {
46956                var iScrollInstance = scrollable.data('iscrollInstance');
46957                iScrollInstance.destroy();
46958
46959                scrollable.data('iscrollInstance', null);
46960            }
46961            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
46962        },
46963
46964        /**
46965         * Called when overflow scrolling has already been setup but the
46966         * window height has potentially changed.
46967         *
46968         * @param  {Object} element      jQuery object containing current section
46969         * @param  {Number} scrollHeight Current window height in pixels
46970         */
46971        update: function(element, scrollHeight) {
46972            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
46973            //short period of time.
46974            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
46975            clearTimeout(iscrollHandler.refreshId);
46976            iscrollHandler.refreshId = setTimeout(function(){
46977                $.each(iscrollHandler.iScrollInstances, function(){
46978                    $(this).get(0).refresh();
46979                });
46980            }, 150);
46981
46982            //updating the wrappers height
46983            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
46984        },
46985
46986        /**
46987         * Called to get any additional elements needed to wrap the section
46988         * content in order to facilitate overflow scrolling.
46989         *
46990         * @return {String|Object} Can be a string containing HTML,
46991         *                         a DOM element, or jQuery object.
46992         */
46993        wrapContent: function() {
46994            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
46995        }
46996    };
46997});
46998
46999(function (global, factory) {
47000	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
47001	typeof define === 'function' && define.amd ? define(['exports'], factory) :
47002	(global = global || self, factory(global.window = global.window || {}));
47003  }(this, (function (exports) { 'use strict';
47004  
47005	function _defineProperties(target, props) {
47006	  for (var i = 0; i < props.length; i++) {
47007		var descriptor = props[i];
47008		descriptor.enumerable = descriptor.enumerable || false;
47009		descriptor.configurable = true;
47010		if ("value" in descriptor) descriptor.writable = true;
47011		Object.defineProperty(target, descriptor.key, descriptor);
47012	  }
47013	}
47014  
47015	function _createClass(Constructor, protoProps, staticProps) {
47016	  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
47017	  if (staticProps) _defineProperties(Constructor, staticProps);
47018	  return Constructor;
47019	}
47020  
47021	/*!
47022	 * Observer 3.12.5
47023	 * https://gsap.com
47024	 *
47025	 * @license Copyright 2008-2024, GreenSock. All rights reserved.
47026	 * Subject to the terms at https://gsap.com/standard-license or for
47027	 * Club GSAP members, the agreement issued with that membership.
47028	 * @author: Jack Doyle, [email protected]
47029	*/
47030	var gsap,
47031		_coreInitted,
47032		_clamp,
47033		_win,
47034		_doc,
47035		_docEl,
47036		_body,
47037		_isTouch,
47038		_pointerType,
47039		ScrollTrigger,
47040		_root,
47041		_normalizer,
47042		_eventTypes,
47043		_context,
47044		_getGSAP = function _getGSAP() {
47045	  return gsap || typeof window !== "undefined" && (gsap = window.gsap) && gsap.registerPlugin && gsap;
47046	},
47047		_startup = 1,
47048		_observers = [],
47049		_scrollers = [],
47050		_proxies = [],
47051		_getTime = Date.now,
47052		_bridge = function _bridge(name, value) {
47053	  return value;
47054	},
47055		_integrate = function _integrate() {
47056	  var core = ScrollTrigger.core,
47057		  data = core.bridge || {},
47058		  scrollers = core._scrollers,
47059		  proxies = core._proxies;
47060	  scrollers.push.apply(scrollers, _scrollers);
47061	  proxies.push.apply(proxies, _proxies);
47062	  _scrollers = scrollers;
47063	  _proxies = proxies;
47064  
47065	  _bridge = function _bridge(name, value) {
47066		return data[name](value);
47067	  };
47068	},
47069		_getProxyProp = function _getProxyProp(element, property) {
47070	  return ~_proxies.indexOf(element) && _proxies[_proxies.indexOf(element) + 1][property];
47071	},
47072		_isViewport = function _isViewport(el) {
47073	  return !!~_root.indexOf(el);
47074	},
47075		_addListener = function _addListener(element, type, func, passive, capture) {
47076	  return element.addEventListener(type, func, {
47077		passive: passive !== false,
47078		capture: !!capture
47079	  });
47080	},
47081		_removeListener = function _removeListener(element, type, func, capture) {
47082	  return element.removeEventListener(type, func, !!capture);
47083	},
47084		_scrollLeft = "scrollLeft",
47085		_scrollTop = "scrollTop",
47086		_onScroll = function _onScroll() {
47087	  return _normalizer && _normalizer.isPressed || _scrollers.cache++;
47088	},
47089		_scrollCacheFunc = function _scrollCacheFunc(f, doNotCache) {
47090	  var cachingFunc = function cachingFunc(value) {
47091		if (value || value === 0) {
47092		  _startup && (_win.history.scrollRestoration = "manual");
47093		  var isNormalizing = _normalizer && _normalizer.isPressed;
47094		  value = cachingFunc.v = Math.round(value) || (_normalizer && _normalizer.iOS ? 1 : 0);
47095		  f(value);
47096		  cachingFunc.cacheID = _scrollers.cache;
47097		  isNormalizing && _bridge("ss", value);
47098		} else if (doNotCache || _scrollers.cache !== cachingFunc.cacheID || _bridge("ref")) {
47099		  cachingFunc.cacheID = _scrollers.cache;
47100		  cachingFunc.v = f();
47101		}
47102  
vendor: 13,754 bytes, lines 47103-47556
47103		return cachingFunc.v + cachingFunc.offset;
47104	  };
47105  
47106	  cachingFunc.offset = 0;
47107	  return f && cachingFunc;
47108	},
47109		_horizontal = {
47110	  s: _scrollLeft,
47111	  p: "left",
47112	  p2: "Left",
47113	  os: "right",
47114	  os2: "Right",
47115	  d: "width",
47116	  d2: "Width",
47117	  a: "x",
47118	  sc: _scrollCacheFunc(function (value) {
47119		return arguments.length ? _win.scrollTo(value, _vertical.sc()) : _win.pageXOffset || _doc[_scrollLeft] || _docEl[_scrollLeft] || _body[_scrollLeft] || 0;
47120	  })
47121	},
47122		_vertical = {
47123	  s: _scrollTop,
47124	  p: "top",
47125	  p2: "Top",
47126	  os: "bottom",
47127	  os2: "Bottom",
47128	  d: "height",
47129	  d2: "Height",
47130	  a: "y",
47131	  op: _horizontal,
47132	  sc: _scrollCacheFunc(function (value) {
47133		return arguments.length ? _win.scrollTo(_horizontal.sc(), value) : _win.pageYOffset || _doc[_scrollTop] || _docEl[_scrollTop] || _body[_scrollTop] || 0;
47134	  })
47135	},
47136		_getTarget = function _getTarget(t, self) {
47137	  return (self && self._ctx && self._ctx.selector || gsap.utils.toArray)(t)[0] || (typeof t === "string" && gsap.config().nullTargetWarn !== false ? console.warn("Element not found:", t) : null);
47138	},
47139		_getScrollFunc = function _getScrollFunc(element, _ref) {
47140	  var s = _ref.s,
47141		  sc = _ref.sc;
47142	  _isViewport(element) && (element = _doc.scrollingElement || _docEl);
47143  
47144	  var i = _scrollers.indexOf(element),
47145		  offset = sc === _vertical.sc ? 1 : 2;
47146  
47147	  !~i && (i = _scrollers.push(element) - 1);
47148	  _scrollers[i + offset] || _addListener(element, "scroll", _onScroll);
47149	  var prev = _scrollers[i + offset],
47150		  func = prev || (_scrollers[i + offset] = _scrollCacheFunc(_getProxyProp(element, s), true) || (_isViewport(element) ? sc : _scrollCacheFunc(function (value) {
47151		return arguments.length ? element[s] = value : element[s];
47152	  })));
47153	  func.target = element;
47154	  prev || (func.smooth = gsap.getProperty(element, "scrollBehavior") === "smooth");
47155	  return func;
47156	},
47157		_getVelocityProp = function _getVelocityProp(value, minTimeRefresh, useDelta) {
47158	  var v1 = value,
47159		  v2 = value,
47160		  t1 = _getTime(),
47161		  t2 = t1,
47162		  min = minTimeRefresh || 50,
47163		  dropToZeroTime = Math.max(500, min * 3),
47164		  update = function update(value, force) {
47165		var t = _getTime();
47166  
47167		if (force || t - t1 > min) {
47168		  v2 = v1;
47169		  v1 = value;
47170		  t2 = t1;
47171		  t1 = t;
47172		} else if (useDelta) {
47173		  v1 += value;
47174		} else {
47175		  v1 = v2 + (value - v2) / (t - t2) * (t1 - t2);
47176		}
47177	  },
47178		  reset = function reset() {
47179		v2 = v1 = useDelta ? 0 : v1;
47180		t2 = t1 = 0;
47181	  },
47182		  getVelocity = function getVelocity(latestValue) {
47183		var tOld = t2,
47184			vOld = v2,
47185			t = _getTime();
47186  
47187		(latestValue || latestValue === 0) && latestValue !== v1 && update(latestValue);
47188		return t1 === t2 || t - t2 > dropToZeroTime ? 0 : (v1 + (useDelta ? vOld : -vOld)) / ((useDelta ? t : t1) - tOld) * 1000;
47189	  };
47190  
47191	  return {
47192		update: update,
47193		reset: reset,
47194		getVelocity: getVelocity
47195	  };
47196	},
47197		_getEvent = function _getEvent(e, preventDefault) {
47198	  preventDefault && !e._gsapAllow && e.preventDefault();
47199	  return e.changedTouches ? e.changedTouches[0] : e;
47200	},
47201		_getAbsoluteMax = function _getAbsoluteMax(a) {
47202	  var max = Math.max.apply(Math, a),
47203		  min = Math.min.apply(Math, a);
47204	  return Math.abs(max) >= Math.abs(min) ? max : min;
47205	},
47206		_setScrollTrigger = function _setScrollTrigger() {
47207	  ScrollTrigger = gsap.core.globals().ScrollTrigger;
47208	  ScrollTrigger && ScrollTrigger.core && _integrate();
47209	},
47210		_initCore = function _initCore(core) {
47211	  gsap = core || _getGSAP();
47212  
47213	  if (!_coreInitted && gsap && typeof document !== "undefined" && document.body) {
47214		_win = window;
47215		_doc = document;
47216		_docEl = _doc.documentElement;
47217		_body = _doc.body;
47218		_root = [_win, _doc, _docEl, _body];
47219		_clamp = gsap.utils.clamp;
47220  
47221		_context = gsap.core.context || function () {};
47222  
47223		_pointerType = "onpointerenter" in _body ? "pointer" : "mouse";
47224		_isTouch = Observer.isTouch = _win.matchMedia && _win.matchMedia("(hover: none), (pointer: coarse)").matches ? 1 : "ontouchstart" in _win || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 ? 2 : 0;
47225		_eventTypes = Observer.eventTypes = ("ontouchstart" in _docEl ? "touchstart,touchmove,touchcancel,touchend" : !("onpointerdown" in _docEl) ? "mousedown,mousemove,mouseup,mouseup" : "pointerdown,pointermove,pointercancel,pointerup").split(",");
47226		setTimeout(function () {
47227		  return _startup = 0;
47228		}, 500);
47229  
47230		_setScrollTrigger();
47231  
47232		_coreInitted = 1;
47233	  }
47234  
47235	  return _coreInitted;
47236	};
47237  
47238	_horizontal.op = _vertical;
47239	_scrollers.cache = 0;
47240	var Observer = function () {
47241	  function Observer(vars) {
47242		this.init(vars);
47243	  }
47244  
47245	  var _proto = Observer.prototype;
47246  
47247	  _proto.init = function init(vars) {
47248		_coreInitted || _initCore(gsap) || console.warn("Please gsap.registerPlugin(Observer)");
47249		ScrollTrigger || _setScrollTrigger();
47250		var tolerance = vars.tolerance,
47251			dragMinimum = vars.dragMinimum,
47252			type = vars.type,
47253			target = vars.target,
47254			lineHeight = vars.lineHeight,
47255			debounce = vars.debounce,
47256			preventDefault = vars.preventDefault,
47257			onStop = vars.onStop,
47258			onStopDelay = vars.onStopDelay,
47259			ignore = vars.ignore,
47260			wheelSpeed = vars.wheelSpeed,
47261			event = vars.event,
47262			onDragStart = vars.onDragStart,
47263			onDragEnd = vars.onDragEnd,
47264			onDrag = vars.onDrag,
47265			onPress = vars.onPress,
47266			onRelease = vars.onRelease,
47267			onRight = vars.onRight,
47268			onLeft = vars.onLeft,
47269			onUp = vars.onUp,
47270			onDown = vars.onDown,
47271			onChangeX = vars.onChangeX,
47272			onChangeY = vars.onChangeY,
47273			onChange = vars.onChange,
47274			onToggleX = vars.onToggleX,
47275			onToggleY = vars.onToggleY,
47276			onHover = vars.onHover,
47277			onHoverEnd = vars.onHoverEnd,
47278			onMove = vars.onMove,
47279			ignoreCheck = vars.ignoreCheck,
47280			isNormalizer = vars.isNormalizer,
47281			onGestureStart = vars.onGestureStart,
47282			onGestureEnd = vars.onGestureEnd,
47283			onWheel = vars.onWheel,
47284			onEnable = vars.onEnable,
47285			onDisable = vars.onDisable,
47286			onClick = vars.onClick,
47287			scrollSpeed = vars.scrollSpeed,
47288			capture = vars.capture,
47289			allowClicks = vars.allowClicks,
47290			lockAxis = vars.lockAxis,
47291			onLockAxis = vars.onLockAxis;
47292		this.target = target = _getTarget(target) || _docEl;
47293		this.vars = vars;
47294		ignore && (ignore = gsap.utils.toArray(ignore));
47295		tolerance = tolerance || 1e-9;
47296		dragMinimum = dragMinimum || 0;
47297		wheelSpeed = wheelSpeed || 1;
47298		scrollSpeed = scrollSpeed || 1;
47299		type = type || "wheel,touch,pointer";
47300		debounce = debounce !== false;
47301		lineHeight || (lineHeight = parseFloat(_win.getComputedStyle(_body).lineHeight) || 22);
47302  
47303		var id,
47304			onStopDelayedCall,
47305			dragged,
47306			moved,
47307			wheeled,
47308			locked,
47309			axis,
47310			self = this,
47311			prevDeltaX = 0,
47312			prevDeltaY = 0,
47313			passive = vars.passive || !preventDefault,
47314			scrollFuncX = _getScrollFunc(target, _horizontal),
47315			scrollFuncY = _getScrollFunc(target, _vertical),
47316			scrollX = scrollFuncX(),
47317			scrollY = scrollFuncY(),
47318			limitToTouch = ~type.indexOf("touch") && !~type.indexOf("pointer") && _eventTypes[0] === "pointerdown",
47319			isViewport = _isViewport(target),
47320			ownerDoc = target.ownerDocument || _doc,
47321			deltaX = [0, 0, 0],
47322			deltaY = [0, 0, 0],
47323			onClickTime = 0,
47324			clickCapture = function clickCapture() {
47325		  return onClickTime = _getTime();
47326		},
47327			_ignoreCheck = function _ignoreCheck(e, isPointerOrTouch) {
47328		  return (self.event = e) && ignore && ~ignore.indexOf(e.target) || isPointerOrTouch && limitToTouch && e.pointerType !== "touch" || ignoreCheck && ignoreCheck(e, isPointerOrTouch);
47329		},
47330			onStopFunc = function onStopFunc() {
47331		  self._vx.reset();
47332  
47333		  self._vy.reset();
47334  
47335		  onStopDelayedCall.pause();
47336		  onStop && onStop(self);
47337		},
47338			update = function update() {
47339		  var dx = self.deltaX = _getAbsoluteMax(deltaX),
47340			  dy = self.deltaY = _getAbsoluteMax(deltaY),
47341			  changedX = Math.abs(dx) >= tolerance,
47342			  changedY = Math.abs(dy) >= tolerance;
47343  
47344		  onChange && (changedX || changedY) && onChange(self, dx, dy, deltaX, deltaY);
47345  
47346		  if (changedX) {
47347			onRight && self.deltaX > 0 && onRight(self);
47348			onLeft && self.deltaX < 0 && onLeft(self);
47349			onChangeX && onChangeX(self);
47350			onToggleX && self.deltaX < 0 !== prevDeltaX < 0 && onToggleX(self);
47351			prevDeltaX = self.deltaX;
47352			deltaX[0] = deltaX[1] = deltaX[2] = 0;
47353		  }
47354  
47355		  if (changedY) {
47356			onDown && self.deltaY > 0 && onDown(self);
47357			onUp && self.deltaY < 0 && onUp(self);
47358			onChangeY && onChangeY(self);
47359			onToggleY && self.deltaY < 0 !== prevDeltaY < 0 && onToggleY(self);
47360			prevDeltaY = self.deltaY;
47361			deltaY[0] = deltaY[1] = deltaY[2] = 0;
47362		  }
47363  
47364		  if (moved || dragged) {
47365			onMove && onMove(self);
47366  
47367			if (dragged) {
47368			  onDrag(self);
47369			  dragged = false;
47370			}
47371  
47372			moved = false;
47373		  }
47374  
47375		  locked && !(locked = false) && onLockAxis && onLockAxis(self);
47376  
47377		  if (wheeled) {
47378			onWheel(self);
47379			wheeled = false;
47380		  }
47381  
47382		  id = 0;
47383		},
47384			onDelta = function onDelta(x, y, index) {
47385		  deltaX[index] += x;
47386		  deltaY[index] += y;
47387  
47388		  self._vx.update(x);
47389  
47390		  self._vy.update(y);
47391  
47392		  debounce ? id || (id = requestAnimationFrame(update)) : update();
47393		},
47394			onTouchOrPointerDelta = function onTouchOrPointerDelta(x, y) {
47395		  if (lockAxis && !axis) {
47396			self.axis = axis = Math.abs(x) > Math.abs(y) ? "x" : "y";
47397			locked = true;
47398		  }
47399  
47400		  if (axis !== "y") {
47401			deltaX[2] += x;
47402  
47403			self._vx.update(x, true);
47404		  }
47405  
47406		  if (axis !== "x") {
47407			deltaY[2] += y;
47408  
47409			self._vy.update(y, true);
47410		  }
47411  
47412		  debounce ? id || (id = requestAnimationFrame(update)) : update();
47413		},
47414			_onDrag = function _onDrag(e) {
47415		  if (_ignoreCheck(e, 1)) {
47416			return;
47417		  }
47418  
47419		  e = _getEvent(e, preventDefault);
47420		  var x = e.clientX,
47421			  y = e.clientY,
47422			  dx = x - self.x,
47423			  dy = y - self.y,
47424			  isDragging = self.isDragging;
47425		  self.x = x;
47426		  self.y = y;
47427  
47428		  if (isDragging || Math.abs(self.startX - x) >= dragMinimum || Math.abs(self.startY - y) >= dragMinimum) {
47429			onDrag && (dragged = true);
47430			isDragging || (self.isDragging = true);
47431			onTouchOrPointerDelta(dx, dy);
47432			isDragging || onDragStart && onDragStart(self);
47433		  }
47434		},
47435			_onPress = self.onPress = function (e) {
47436		  if (_ignoreCheck(e, 1) || e && e.button) {
47437			return;
47438		  }
47439  
47440		  self.axis = axis = null;
47441		  onStopDelayedCall.pause();
47442		  self.isPressed = true;
47443		  e = _getEvent(e);
47444		  prevDeltaX = prevDeltaY = 0;
47445		  self.startX = self.x = e.clientX;
47446		  self.startY = self.y = e.clientY;
47447  
47448		  self._vx.reset();
47449  
47450		  self._vy.reset();
47451  
47452		  _addListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, passive, true);
47453  
47454		  self.deltaX = self.deltaY = 0;
47455		  onPress && onPress(self);
47456		},
47457			_onRelease = self.onRelease = function (e) {
47458		  if (_ignoreCheck(e, 1)) {
47459			return;
47460		  }
47461  
47462		  _removeListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, true);
47463  
47464		  var isTrackingDrag = !isNaN(self.y - self.startY),
47465			  wasDragging = self.isDragging,
47466			  isDragNotClick = wasDragging && (Math.abs(self.x - self.startX) > 3 || Math.abs(self.y - self.startY) > 3),
47467			  eventData = _getEvent(e);
47468  
47469		  if (!isDragNotClick && isTrackingDrag) {
47470			self._vx.reset();
47471  
47472			self._vy.reset();
47473  
47474			if (preventDefault && allowClicks) {
47475			  gsap.delayedCall(0.08, function () {
47476				if (_getTime() - onClickTime > 300 && !e.defaultPrevented) {
47477				  if (e.target.click) {
47478					e.target.click();
47479				  } else if (ownerDoc.createEvent) {
47480					var syntheticEvent = ownerDoc.createEvent("MouseEvents");
47481					syntheticEvent.initMouseEvent("click", true, true, _win, 1, eventData.screenX, eventData.screenY, eventData.clientX, eventData.clientY, false, false, false, false, 0, null);
47482					e.target.dispatchEvent(syntheticEvent);
47483				  }
47484				}
47485			  });
47486			}
47487		  }
47488  
47489		  self.isDragging = self.isGesturing = self.isPressed = false;
47490		  onStop && wasDragging && !isNormalizer && onStopDelayedCall.restart(true);
47491		  onDragEnd && wasDragging && onDragEnd(self);
47492		  onRelease && onRelease(self, isDragNotClick);
47493		},
47494			_onGestureStart = function _onGestureStart(e) {
47495		  return e.touches && e.touches.length > 1 && (self.isGesturing = true) && onGestureStart(e, self.isDragging);
47496		},
47497			_onGestureEnd = function _onGestureEnd() {
47498		  return (self.isGesturing = false) || onGestureEnd(self);
47499		},
47500			onScroll = function onScroll(e) {
47501		  if (_ignoreCheck(e)) {
47502			return;
47503		  }
47504  
47505		  var x = scrollFuncX(),
47506			  y = scrollFuncY();
47507		  onDelta((x - scrollX) * scrollSpeed, (y - scrollY) * scrollSpeed, 1);
47508		  scrollX = x;
47509		  scrollY = y;
47510		  onStop && onStopDelayedCall.restart(true);
47511		},
47512			_onWheel = function _onWheel(e) {
47513		  if (_ignoreCheck(e)) {
47514			return;
47515		  }
47516  
47517		  e = _getEvent(e, preventDefault);
47518		  onWheel && (wheeled = true);
47519		  var multiplier = (e.deltaMode === 1 ? lineHeight : e.deltaMode === 2 ? _win.innerHeight : 1) * wheelSpeed;
47520		  onDelta(e.deltaX * multiplier, e.deltaY * multiplier, 0);
47521		  onStop && !isNormalizer && onStopDelayedCall.restart(true);
47522		},
47523			_onMove = function _onMove(e) {
47524		  if (_ignoreCheck(e)) {
47525			return;
47526		  }
47527  
47528		  var x = e.clientX,
47529			  y = e.clientY,
47530			  dx = x - self.x,
47531			  dy = y - self.y;
47532		  self.x = x;
47533		  self.y = y;
47534		  moved = true;
47535		  onStop && onStopDelayedCall.restart(true);
47536		  (dx || dy) && onTouchOrPointerDelta(dx, dy);
47537		},
47538			_onHover = function _onHover(e) {
47539		  self.event = e;
47540		  onHover(self);
47541		},
47542			_onHoverEnd = function _onHoverEnd(e) {
47543		  self.event = e;
47544		  onHoverEnd(self);
47545		},
47546			_onClick = function _onClick(e) {
47547		  return _ignoreCheck(e) || _getEvent(e, preventDefault) && onClick(self);
47548		};
47549  
47550		onStopDelayedCall = self._dc = gsap.delayedCall(onStopDelay || 0.25, onStopFunc).pause();
47551		self.deltaX = self.deltaY = 0;
47552		self._vx = _getVelocityProp(0, 50, true);
47553		self._vy = _getVelocityProp(0, 50, true);
47554		self.scrollX = scrollFuncX;
47555		self.scrollY = scrollFuncY;
47556		self.isDragging = self.isGesturing = self.isPressed = false;
vendor: 7,173 bytes, lines 47557-47799
47557  
47558		_context(this);
47559  
47560		self.enable = function (e) {
47561		  if (!self.isEnabled) {
47562			_addListener(isViewport ? ownerDoc : target, "scroll", _onScroll);
47563  
47564			type.indexOf("scroll") >= 0 && _addListener(isViewport ? ownerDoc : target, "scroll", onScroll, passive, capture);
47565			type.indexOf("wheel") >= 0 && _addListener(target, "wheel", _onWheel, passive, capture);
47566  
47567			if (type.indexOf("touch") >= 0 && _isTouch || type.indexOf("pointer") >= 0) {
47568			  _addListener(target, _eventTypes[0], _onPress, passive, capture);
47569  
47570			  _addListener(ownerDoc, _eventTypes[2], _onRelease);
47571  
47572			  _addListener(ownerDoc, _eventTypes[3], _onRelease);
47573  
47574			  allowClicks && _addListener(target, "click", clickCapture, true, true);
47575			  onClick && _addListener(target, "click", _onClick);
47576			  onGestureStart && _addListener(ownerDoc, "gesturestart", _onGestureStart);
47577			  onGestureEnd && _addListener(ownerDoc, "gestureend", _onGestureEnd);
47578			  onHover && _addListener(target, _pointerType + "enter", _onHover);
47579			  onHoverEnd && _addListener(target, _pointerType + "leave", _onHoverEnd);
47580			  onMove && _addListener(target, _pointerType + "move", _onMove);
47581			}
47582  
47583			self.isEnabled = true;
47584			e && e.type && _onPress(e);
47585			onEnable && onEnable(self);
47586		  }
47587  
47588		  return self;
47589		};
47590  
47591		self.disable = function () {
47592		  if (self.isEnabled) {
47593			_observers.filter(function (o) {
47594			  return o !== self && _isViewport(o.target);
47595			}).length || _removeListener(isViewport ? ownerDoc : target, "scroll", _onScroll);
47596  
47597			if (self.isPressed) {
47598			  self._vx.reset();
47599  
47600			  self._vy.reset();
47601  
47602			  _removeListener(isNormalizer ? target : ownerDoc, _eventTypes[1], _onDrag, true);
47603			}
47604  
47605			_removeListener(isViewport ? ownerDoc : target, "scroll", onScroll, capture);
47606  
47607			_removeListener(target, "wheel", _onWheel, capture);
47608  
47609			_removeListener(target, _eventTypes[0], _onPress, capture);
47610  
47611			_removeListener(ownerDoc, _eventTypes[2], _onRelease);
47612  
47613			_removeListener(ownerDoc, _eventTypes[3], _onRelease);
47614  
47615			_removeListener(target, "click", clickCapture, true);
47616  
47617			_removeListener(target, "click", _onClick);
47618  
47619			_removeListener(ownerDoc, "gesturestart", _onGestureStart);
47620  
47621			_removeListener(ownerDoc, "gestureend", _onGestureEnd);
47622  
47623			_removeListener(target, _pointerType + "enter", _onHover);
47624  
47625			_removeListener(target, _pointerType + "leave", _onHoverEnd);
47626  
47627			_removeListener(target, _pointerType + "move", _onMove);
47628  
47629			self.isEnabled = self.isPressed = self.isDragging = false;
47630			onDisable && onDisable(self);
47631		  }
47632		};
47633  
47634		self.kill = self.revert = function () {
47635		  self.disable();
47636  
47637		  var i = _observers.indexOf(self);
47638  
47639		  i >= 0 && _observers.splice(i, 1);
47640		  _normalizer === self && (_normalizer = 0);
47641		};
47642  
47643		_observers.push(self);
47644  
47645		isNormalizer && _isViewport(target) && (_normalizer = self);
47646		self.enable(event);
47647	  };
47648  
47649	  _createClass(Observer, [{
47650		key: "velocityX",
47651		get: function get() {
47652		  return this._vx.getVelocity();
47653		}
47654	  }, {
47655		key: "velocityY",
47656		get: function get() {
47657		  return this._vy.getVelocity();
47658		}
47659	  }]);
47660  
47661	  return Observer;
47662	}();
47663	Observer.version = "3.12.5";
47664  
47665	Observer.create = function (vars) {
47666	  return new Observer(vars);
47667	};
47668  
47669	Observer.register = _initCore;
47670  
47671	Observer.getAll = function () {
47672	  return _observers.slice();
47673	};
47674  
47675	Observer.getById = function (id) {
47676	  return _observers.filter(function (o) {
47677		return o.vars.id === id;
47678	  })[0];
47679	};
47680  
47681	_getGSAP() && gsap.registerPlugin(Observer);
47682  
47683	/*!
47684	 * ScrollTrigger 3.12.5
47685	 * https://gsap.com
47686	 *
47687	 * @license Copyright 2008-2024, GreenSock. All rights reserved.
47688	 * Subject to the terms at https://gsap.com/standard-license or for
47689	 * Club GSAP members, the agreement issued with that membership.
47690	 * @author: Jack Doyle, [email protected]
47691	*/
47692  
47693	var gsap$1,
47694		_coreInitted$1,
47695		_win$1,
47696		_doc$1,
47697		_docEl$1,
47698		_body$1,
47699		_root$1,
47700		_resizeDelay,
47701		_toArray,
47702		_clamp$1,
47703		_time2,
47704		_syncInterval,
47705		_refreshing,
47706		_pointerIsDown,
47707		_transformProp,
47708		_i,
47709		_prevWidth,
47710		_prevHeight,
47711		_autoRefresh,
47712		_sort,
47713		_suppressOverwrites,
47714		_ignoreResize,
47715		_normalizer$1,
47716		_ignoreMobileResize,
47717		_baseScreenHeight,
47718		_baseScreenWidth,
47719		_fixIOSBug,
47720		_context$1,
47721		_scrollRestoration,
47722		_div100vh,
47723		_100vh,
47724		_isReverted,
47725		_clampingMax,
47726		_limitCallbacks,
47727		_startup$1 = 1,
47728		_getTime$1 = Date.now,
47729		_time1 = _getTime$1(),
47730		_lastScrollTime = 0,
47731		_enabled = 0,
47732		_parseClamp = function _parseClamp(value, type, self) {
47733	  var clamp = _isString(value) && (value.substr(0, 6) === "clamp(" || value.indexOf("max") > -1);
47734	  self["_" + type + "Clamp"] = clamp;
47735	  return clamp ? value.substr(6, value.length - 7) : value;
47736	},
47737		_keepClamp = function _keepClamp(value, clamp) {
47738	  return clamp && (!_isString(value) || value.substr(0, 6) !== "clamp(") ? "clamp(" + value + ")" : value;
47739	},
47740		_rafBugFix = function _rafBugFix() {
47741	  return _enabled && requestAnimationFrame(_rafBugFix);
47742	},
47743		_pointerDownHandler = function _pointerDownHandler() {
47744	  return _pointerIsDown = 1;
47745	},
47746		_pointerUpHandler = function _pointerUpHandler() {
47747	  return _pointerIsDown = 0;
47748	},
47749		_passThrough = function _passThrough(v) {
47750	  return v;
47751	},
47752		_round = function _round(value) {
47753	  return Math.round(value * 100000) / 100000 || 0;
47754	},
47755		_windowExists = function _windowExists() {
47756	  return typeof window !== "undefined";
47757	},
47758		_getGSAP$1 = function _getGSAP() {
47759	  return gsap$1 || _windowExists() && (gsap$1 = window.gsap) && gsap$1.registerPlugin && gsap$1;
47760	},
47761		_isViewport$1 = function _isViewport(e) {
47762	  return !!~_root$1.indexOf(e);
47763	},
47764		_getViewportDimension = function _getViewportDimension(dimensionProperty) {
47765	  return (dimensionProperty === "Height" ? _100vh : _win$1["inner" + dimensionProperty]) || _docEl$1["client" + dimensionProperty] || _body$1["client" + dimensionProperty];
47766	},
47767		_getBoundsFunc = function _getBoundsFunc(element) {
47768	  return _getProxyProp(element, "getBoundingClientRect") || (_isViewport$1(element) ? function () {
47769		_winOffsets.width = _win$1.innerWidth;
47770		_winOffsets.height = _100vh;
47771		return _winOffsets;
47772	  } : function () {
47773		return _getBounds(element);
47774	  });
47775	},
47776		_getSizeFunc = function _getSizeFunc(scroller, isViewport, _ref) {
47777	  var d = _ref.d,
47778		  d2 = _ref.d2,
47779		  a = _ref.a;
47780	  return (a = _getProxyProp(scroller, "getBoundingClientRect")) ? function () {
47781		return a()[d];
47782	  } : function () {
47783		return (isViewport ? _getViewportDimension(d2) : scroller["client" + d2]) || 0;
47784	  };
47785	},
47786		_getOffsetsFunc = function _getOffsetsFunc(element, isViewport) {
47787	  return !isViewport || ~_proxies.indexOf(element) ? _getBoundsFunc(element) : function () {
47788		return _winOffsets;
47789	  };
47790	},
47791		_maxScroll = function _maxScroll(element, _ref2) {
47792	  var s = _ref2.s,
47793		  d2 = _ref2.d2,
47794		  d = _ref2.d,
47795		  a = _ref2.a;
47796	  return Math.max(0, (s = "scroll" + d2) && (a = _getProxyProp(element, s)) ? a() - _getBoundsFunc(element)()[d] : _isViewport$1(element) ? (_docEl$1[s] || _body$1[s]) - _getViewportDimension(d2) : element[s] - element["offset" + d2]);
47797	},
47798		_iterateAutoRefresh = function _iterateAutoRefresh(func, events) {
47799	  for (var i = 0; i < _autoRefresh.length; i += 3) {
vendor: 4,900 bytes, lines 47800-47981
47800		(!events || ~events.indexOf(_autoRefresh[i + 1])) && func(_autoRefresh[i], _autoRefresh[i + 1], _autoRefresh[i + 2]);
47801	  }
47802	},
47803		_isString = function _isString(value) {
47804	  return typeof value === "string";
47805	},
47806		_isFunction = function _isFunction(value) {
47807	  return typeof value === "function";
47808	},
47809		_isNumber = function _isNumber(value) {
47810	  return typeof value === "number";
47811	},
47812		_isObject = function _isObject(value) {
47813	  return typeof value === "object";
47814	},
47815		_endAnimation = function _endAnimation(animation, reversed, pause) {
47816	  return animation && animation.progress(reversed ? 0 : 1) && pause && animation.pause();
47817	},
47818		_callback = function _callback(self, func) {
47819	  if (self.enabled) {
47820		var result = self._ctx ? self._ctx.add(function () {
47821		  return func(self);
47822		}) : func(self);
47823		result && result.totalTime && (self.callbackAnimation = result);
47824	  }
47825	},
47826		_abs = Math.abs,
47827		_left = "left",
47828		_top = "top",
47829		_right = "right",
47830		_bottom = "bottom",
47831		_width = "width",
47832		_height = "height",
47833		_Right = "Right",
47834		_Left = "Left",
47835		_Top = "Top",
47836		_Bottom = "Bottom",
47837		_padding = "padding",
47838		_margin = "margin",
47839		_Width = "Width",
47840		_Height = "Height",
47841		_px = "px",
47842		_getComputedStyle = function _getComputedStyle(element) {
47843	  return _win$1.getComputedStyle(element);
47844	},
47845		_makePositionable = function _makePositionable(element) {
47846	  var position = _getComputedStyle(element).position;
47847  
47848	  element.style.position = position === "absolute" || position === "fixed" ? position : "relative";
47849	},
47850		_setDefaults = function _setDefaults(obj, defaults) {
47851	  for (var p in defaults) {
47852		p in obj || (obj[p] = defaults[p]);
47853	  }
47854  
47855	  return obj;
47856	},
47857		_getBounds = function _getBounds(element, withoutTransforms) {
47858	  var tween = withoutTransforms && _getComputedStyle(element)[_transformProp] !== "matrix(1, 0, 0, 1, 0, 0)" && gsap$1.to(element, {
47859		x: 0,
47860		y: 0,
47861		xPercent: 0,
47862		yPercent: 0,
47863		rotation: 0,
47864		rotationX: 0,
47865		rotationY: 0,
47866		scale: 1,
47867		skewX: 0,
47868		skewY: 0
47869	  }).progress(1),
47870		  bounds = element.getBoundingClientRect();
47871	  tween && tween.progress(0).kill();
47872	  return bounds;
47873	},
47874		_getSize = function _getSize(element, _ref3) {
47875	  var d2 = _ref3.d2;
47876	  return element["offset" + d2] || element["client" + d2] || 0;
47877	},
47878		_getLabelRatioArray = function _getLabelRatioArray(timeline) {
47879	  var a = [],
47880		  labels = timeline.labels,
47881		  duration = timeline.duration(),
47882		  p;
47883  
47884	  for (p in labels) {
47885		a.push(labels[p] / duration);
47886	  }
47887  
47888	  return a;
47889	},
47890		_getClosestLabel = function _getClosestLabel(animation) {
47891	  return function (value) {
47892		return gsap$1.utils.snap(_getLabelRatioArray(animation), value);
47893	  };
47894	},
47895		_snapDirectional = function _snapDirectional(snapIncrementOrArray) {
47896	  var snap = gsap$1.utils.snap(snapIncrementOrArray),
47897		  a = Array.isArray(snapIncrementOrArray) && snapIncrementOrArray.slice(0).sort(function (a, b) {
47898		return a - b;
47899	  });
47900	  return a ? function (value, direction, threshold) {
47901		if (threshold === void 0) {
47902		  threshold = 1e-3;
47903		}
47904  
47905		var i;
47906  
47907		if (!direction) {
47908		  return snap(value);
47909		}
47910  
47911		if (direction > 0) {
47912		  value -= threshold;
47913  
47914		  for (i = 0; i < a.length; i++) {
47915			if (a[i] >= value) {
47916			  return a[i];
47917			}
47918		  }
47919  
47920		  return a[i - 1];
47921		} else {
47922		  i = a.length;
47923		  value += threshold;
47924  
47925		  while (i--) {
47926			if (a[i] <= value) {
47927			  return a[i];
47928			}
47929		  }
47930		}
47931  
47932		return a[0];
47933	  } : function (value, direction, threshold) {
47934		if (threshold === void 0) {
47935		  threshold = 1e-3;
47936		}
47937  
47938		var snapped = snap(value);
47939		return !direction || Math.abs(snapped - value) < threshold || snapped - value < 0 === direction < 0 ? snapped : snap(direction < 0 ? value - snapIncrementOrArray : value + snapIncrementOrArray);
47940	  };
47941	},
47942		_getLabelAtDirection = function _getLabelAtDirection(timeline) {
47943	  return function (value, st) {
47944		return _snapDirectional(_getLabelRatioArray(timeline))(value, st.direction);
47945	  };
47946	},
47947		_multiListener = function _multiListener(func, element, types, callback) {
47948	  return types.split(",").forEach(function (type) {
47949		return func(element, type, callback);
47950	  });
47951	},
47952		_addListener$1 = function _addListener(element, type, func, nonPassive, capture) {
47953	  return element.addEventListener(type, func, {
47954		passive: !nonPassive,
47955		capture: !!capture
47956	  });
47957	},
47958		_removeListener$1 = function _removeListener(element, type, func, capture) {
47959	  return element.removeEventListener(type, func, !!capture);
47960	},
47961		_wheelListener = function _wheelListener(func, el, scrollFunc) {
47962	  scrollFunc = scrollFunc && scrollFunc.wheelHandler;
47963  
47964	  if (scrollFunc) {
47965		func(el, "wheel", scrollFunc);
47966		func(el, "touchmove", scrollFunc);
47967	  }
47968	},
47969		_markerDefaults = {
47970	  startColor: "green",
47971	  endColor: "red",
47972	  indent: 0,
47973	  fontSize: "16px",
47974	  fontWeight: "normal"
47975	},
47976		_defaults = {
47977	  toggleActions: "play",
47978	  anticipatePin: 0
47979	},
47980		_keywords = {
47981	  top: 0,
vendor: 14,119 bytes, lines 47982-48422
47982	  left: 0,
47983	  center: 0.5,
47984	  bottom: 1,
47985	  right: 1
47986	},
47987		_offsetToPx = function _offsetToPx(value, size) {
47988	  if (_isString(value)) {
47989		var eqIndex = value.indexOf("="),
47990			relative = ~eqIndex ? +(value.charAt(eqIndex - 1) + 1) * parseFloat(value.substr(eqIndex + 1)) : 0;
47991  
47992		if (~eqIndex) {
47993		  value.indexOf("%") > eqIndex && (relative *= size / 100);
47994		  value = value.substr(0, eqIndex - 1);
47995		}
47996  
47997		value = relative + (value in _keywords ? _keywords[value] * size : ~value.indexOf("%") ? parseFloat(value) * size / 100 : parseFloat(value) || 0);
47998	  }
47999  
48000	  return value;
48001	},
48002		_createMarker = function _createMarker(type, name, container, direction, _ref4, offset, matchWidthEl, containerAnimation) {
48003	  var startColor = _ref4.startColor,
48004		  endColor = _ref4.endColor,
48005		  fontSize = _ref4.fontSize,
48006		  indent = _ref4.indent,
48007		  fontWeight = _ref4.fontWeight;
48008  
48009	  var e = _doc$1.createElement("div"),
48010		  useFixedPosition = _isViewport$1(container) || _getProxyProp(container, "pinType") === "fixed",
48011		  isScroller = type.indexOf("scroller") !== -1,
48012		  parent = useFixedPosition ? _body$1 : container,
48013		  isStart = type.indexOf("start") !== -1,
48014		  color = isStart ? startColor : endColor,
48015		  css = "border-color:" + color + ";font-size:" + fontSize + ";color:" + color + ";font-weight:" + fontWeight + ";pointer-events:none;white-space:nowrap;font-family:sans-serif,Arial;z-index:1000;padding:4px 8px;border-width:0;border-style:solid;";
48016  
48017	  css += "position:" + ((isScroller || containerAnimation) && useFixedPosition ? "fixed;" : "absolute;");
48018	  (isScroller || containerAnimation || !useFixedPosition) && (css += (direction === _vertical ? _right : _bottom) + ":" + (offset + parseFloat(indent)) + "px;");
48019	  matchWidthEl && (css += "box-sizing:border-box;text-align:left;width:" + matchWidthEl.offsetWidth + "px;");
48020	  e._isStart = isStart;
48021	  e.setAttribute("class", "gsap-marker-" + type + (name ? " marker-" + name : ""));
48022	  e.style.cssText = css;
48023	  e.innerText = name || name === 0 ? type + "-" + name : type;
48024	  parent.children[0] ? parent.insertBefore(e, parent.children[0]) : parent.appendChild(e);
48025	  e._offset = e["offset" + direction.op.d2];
48026  
48027	  _positionMarker(e, 0, direction, isStart);
48028  
48029	  return e;
48030	},
48031		_positionMarker = function _positionMarker(marker, start, direction, flipped) {
48032	  var vars = {
48033		display: "block"
48034	  },
48035		  side = direction[flipped ? "os2" : "p2"],
48036		  oppositeSide = direction[flipped ? "p2" : "os2"];
48037	  marker._isFlipped = flipped;
48038	  vars[direction.a + "Percent"] = flipped ? -100 : 0;
48039	  vars[direction.a] = flipped ? "1px" : 0;
48040	  vars["border" + side + _Width] = 1;
48041	  vars["border" + oppositeSide + _Width] = 0;
48042	  vars[direction.p] = start + "px";
48043	  gsap$1.set(marker, vars);
48044	},
48045		_triggers = [],
48046		_ids = {},
48047		_rafID,
48048		_sync = function _sync() {
48049	  return _getTime$1() - _lastScrollTime > 34 && (_rafID || (_rafID = requestAnimationFrame(_updateAll)));
48050	},
48051		_onScroll$1 = function _onScroll() {
48052	  if (!_normalizer$1 || !_normalizer$1.isPressed || _normalizer$1.startX > _body$1.clientWidth) {
48053		_scrollers.cache++;
48054  
48055		if (_normalizer$1) {
48056		  _rafID || (_rafID = requestAnimationFrame(_updateAll));
48057		} else {
48058		  _updateAll();
48059		}
48060  
48061		_lastScrollTime || _dispatch("scrollStart");
48062		_lastScrollTime = _getTime$1();
48063	  }
48064	},
48065		_setBaseDimensions = function _setBaseDimensions() {
48066	  _baseScreenWidth = _win$1.innerWidth;
48067	  _baseScreenHeight = _win$1.innerHeight;
48068	},
48069		_onResize = function _onResize() {
48070	  _scrollers.cache++;
48071	  !_refreshing && !_ignoreResize && !_doc$1.fullscreenElement && !_doc$1.webkitFullscreenElement && (!_ignoreMobileResize || _baseScreenWidth !== _win$1.innerWidth || Math.abs(_win$1.innerHeight - _baseScreenHeight) > _win$1.innerHeight * 0.25) && _resizeDelay.restart(true);
48072	},
48073		_listeners = {},
48074		_emptyArray = [],
48075		_softRefresh = function _softRefresh() {
48076	  return _removeListener$1(ScrollTrigger$1, "scrollEnd", _softRefresh) || _refreshAll(true);
48077	},
48078		_dispatch = function _dispatch(type) {
48079	  return _listeners[type] && _listeners[type].map(function (f) {
48080		return f();
48081	  }) || _emptyArray;
48082	},
48083		_savedStyles = [],
48084		_revertRecorded = function _revertRecorded(media) {
48085	  for (var i = 0; i < _savedStyles.length; i += 5) {
48086		if (!media || _savedStyles[i + 4] && _savedStyles[i + 4].query === media) {
48087		  _savedStyles[i].style.cssText = _savedStyles[i + 1];
48088		  _savedStyles[i].getBBox && _savedStyles[i].setAttribute("transform", _savedStyles[i + 2] || "");
48089		  _savedStyles[i + 3].uncache = 1;
48090		}
48091	  }
48092	},
48093		_revertAll = function _revertAll(kill, media) {
48094	  var trigger;
48095  
48096	  for (_i = 0; _i < _triggers.length; _i++) {
48097		trigger = _triggers[_i];
48098  
48099		if (trigger && (!media || trigger._ctx === media)) {
48100		  if (kill) {
48101			trigger.kill(1);
48102		  } else {
48103			trigger.revert(true, true);
48104		  }
48105		}
48106	  }
48107  
48108	  _isReverted = true;
48109	  media && _revertRecorded(media);
48110	  media || _dispatch("revert");
48111	},
48112		_clearScrollMemory = function _clearScrollMemory(scrollRestoration, force) {
48113	  _scrollers.cache++;
48114	  (force || !_refreshingAll) && _scrollers.forEach(function (obj) {
48115		return _isFunction(obj) && obj.cacheID++ && (obj.rec = 0);
48116	  });
48117	  _isString(scrollRestoration) && (_win$1.history.scrollRestoration = _scrollRestoration = scrollRestoration);
48118	},
48119		_refreshingAll,
48120		_refreshID = 0,
48121		_queueRefreshID,
48122		_queueRefreshAll = function _queueRefreshAll() {
48123	  if (_queueRefreshID !== _refreshID) {
48124		var id = _queueRefreshID = _refreshID;
48125		requestAnimationFrame(function () {
48126		  return id === _refreshID && _refreshAll(true);
48127		});
48128	  }
48129	},
48130		_refresh100vh = function _refresh100vh() {
48131	  _body$1.appendChild(_div100vh);
48132  
48133	  _100vh = !_normalizer$1 && _div100vh.offsetHeight || _win$1.innerHeight;
48134  
48135	  _body$1.removeChild(_div100vh);
48136	},
48137		_hideAllMarkers = function _hideAllMarkers(hide) {
48138	  return _toArray(".gsap-marker-start, .gsap-marker-end, .gsap-marker-scroller-start, .gsap-marker-scroller-end").forEach(function (el) {
48139		return el.style.display = hide ? "none" : "block";
48140	  });
48141	},
48142		_refreshAll = function _refreshAll(force, skipRevert) {
48143	  if (_lastScrollTime && !force && !_isReverted) {
48144		_addListener$1(ScrollTrigger$1, "scrollEnd", _softRefresh);
48145  
48146		return;
48147	  }
48148  
48149	  _refresh100vh();
48150  
48151	  _refreshingAll = ScrollTrigger$1.isRefreshing = true;
48152  
48153	  _scrollers.forEach(function (obj) {
48154		return _isFunction(obj) && ++obj.cacheID && (obj.rec = obj());
48155	  });
48156  
48157	  var refreshInits = _dispatch("refreshInit");
48158  
48159	  _sort && ScrollTrigger$1.sort();
48160	  skipRevert || _revertAll();
48161  
48162	  _scrollers.forEach(function (obj) {
48163		if (_isFunction(obj)) {
48164		  obj.smooth && (obj.target.style.scrollBehavior = "auto");
48165		  obj(0);
48166		}
48167	  });
48168  
48169	  _triggers.slice(0).forEach(function (t) {
48170		return t.refresh();
48171	  });
48172  
48173	  _isReverted = false;
48174  
48175	  _triggers.forEach(function (t) {
48176		if (t._subPinOffset && t.pin) {
48177		  var prop = t.vars.horizontal ? "offsetWidth" : "offsetHeight",
48178			  original = t.pin[prop];
48179		  t.revert(true, 1);
48180		  t.adjustPinSpacing(t.pin[prop] - original);
48181		  t.refresh();
48182		}
48183	  });
48184  
48185	  _clampingMax = 1;
48186  
48187	  _hideAllMarkers(true);
48188  
48189	  _triggers.forEach(function (t) {
48190		var max = _maxScroll(t.scroller, t._dir),
48191			endClamp = t.vars.end === "max" || t._endClamp && t.end > max,
48192			startClamp = t._startClamp && t.start >= max;
48193  
48194		(endClamp || startClamp) && t.setPositions(startClamp ? max - 1 : t.start, endClamp ? Math.max(startClamp ? max : t.start + 1, max) : t.end, true);
48195	  });
48196  
48197	  _hideAllMarkers(false);
48198  
48199	  _clampingMax = 0;
48200	  refreshInits.forEach(function (result) {
48201		return result && result.render && result.render(-1);
48202	  });
48203  
48204	  _scrollers.forEach(function (obj) {
48205		if (_isFunction(obj)) {
48206		  obj.smooth && requestAnimationFrame(function () {
48207			return obj.target.style.scrollBehavior = "smooth";
48208		  });
48209		  obj.rec && obj(obj.rec);
48210		}
48211	  });
48212  
48213	  _clearScrollMemory(_scrollRestoration, 1);
48214  
48215	  _resizeDelay.pause();
48216  
48217	  _refreshID++;
48218	  _refreshingAll = 2;
48219  
48220	  _updateAll(2);
48221  
48222	  _triggers.forEach(function (t) {
48223		return _isFunction(t.vars.onRefresh) && t.vars.onRefresh(t);
48224	  });
48225  
48226	  _refreshingAll = ScrollTrigger$1.isRefreshing = false;
48227  
48228	  _dispatch("refresh");
48229	},
48230		_lastScroll = 0,
48231		_direction = 1,
48232		_primary,
48233		_updateAll = function _updateAll(force) {
48234	  if (force === 2 || !_refreshingAll && !_isReverted) {
48235		ScrollTrigger$1.isUpdating = true;
48236		_primary && _primary.update(0);
48237  
48238		var l = _triggers.length,
48239			time = _getTime$1(),
48240			recordVelocity = time - _time1 >= 50,
48241			scroll = l && _triggers[0].scroll();
48242  
48243		_direction = _lastScroll > scroll ? -1 : 1;
48244		_refreshingAll || (_lastScroll = scroll);
48245  
48246		if (recordVelocity) {
48247		  if (_lastScrollTime && !_pointerIsDown && time - _lastScrollTime > 200) {
48248			_lastScrollTime = 0;
48249  
48250			_dispatch("scrollEnd");
48251		  }
48252  
48253		  _time2 = _time1;
48254		  _time1 = time;
48255		}
48256  
48257		if (_direction < 0) {
48258		  _i = l;
48259  
48260		  while (_i-- > 0) {
48261			_triggers[_i] && _triggers[_i].update(0, recordVelocity);
48262		  }
48263  
48264		  _direction = 1;
48265		} else {
48266		  for (_i = 0; _i < l; _i++) {
48267			_triggers[_i] && _triggers[_i].update(0, recordVelocity);
48268		  }
48269		}
48270  
48271		ScrollTrigger$1.isUpdating = false;
48272	  }
48273  
48274	  _rafID = 0;
48275	},
48276		_propNamesToCopy = [_left, _top, _bottom, _right, _margin + _Bottom, _margin + _Right, _margin + _Top, _margin + _Left, "display", "flexShrink", "float", "zIndex", "gridColumnStart", "gridColumnEnd", "gridRowStart", "gridRowEnd", "gridArea", "justifySelf", "alignSelf", "placeSelf", "order"],
48277		_stateProps = _propNamesToCopy.concat([_width, _height, "boxSizing", "max" + _Width, "max" + _Height, "position", _margin, _padding, _padding + _Top, _padding + _Right, _padding + _Bottom, _padding + _Left]),
48278		_swapPinOut = function _swapPinOut(pin, spacer, state) {
48279	  _setState(state);
48280  
48281	  var cache = pin._gsap;
48282  
48283	  if (cache.spacerIsNative) {
48284		_setState(cache.spacerState);
48285	  } else if (pin._gsap.swappedIn) {
48286		var parent = spacer.parentNode;
48287  
48288		if (parent) {
48289		  parent.insertBefore(pin, spacer);
48290		  parent.removeChild(spacer);
48291		}
48292	  }
48293  
48294	  pin._gsap.swappedIn = false;
48295	},
48296		_swapPinIn = function _swapPinIn(pin, spacer, cs, spacerState) {
48297	  if (!pin._gsap.swappedIn) {
48298		var i = _propNamesToCopy.length,
48299			spacerStyle = spacer.style,
48300			pinStyle = pin.style,
48301			p;
48302  
48303		while (i--) {
48304		  p = _propNamesToCopy[i];
48305		  spacerStyle[p] = cs[p];
48306		}
48307  
48308		spacerStyle.position = cs.position === "absolute" ? "absolute" : "relative";
48309		cs.display === "inline" && (spacerStyle.display = "inline-block");
48310		pinStyle[_bottom] = pinStyle[_right] = "auto";
48311		spacerStyle.flexBasis = cs.flexBasis || "auto";
48312		spacerStyle.overflow = "visible";
48313		spacerStyle.boxSizing = "border-box";
48314		spacerStyle[_width] = _getSize(pin, _horizontal) + _px;
48315		spacerStyle[_height] = _getSize(pin, _vertical) + _px;
48316		spacerStyle[_padding] = pinStyle[_margin] = pinStyle[_top] = pinStyle[_left] = "0";
48317  
48318		_setState(spacerState);
48319  
48320		pinStyle[_width] = pinStyle["max" + _Width] = cs[_width];
48321		pinStyle[_height] = pinStyle["max" + _Height] = cs[_height];
48322		pinStyle[_padding] = cs[_padding];
48323  
48324		if (pin.parentNode !== spacer) {
48325		  pin.parentNode.insertBefore(spacer, pin);
48326		  spacer.appendChild(pin);
48327		}
48328  
48329		pin._gsap.swappedIn = true;
48330	  }
48331	},
48332		_capsExp = /([A-Z])/g,
48333		_setState = function _setState(state) {
48334	  if (state) {
48335		var style = state.t.style,
48336			l = state.length,
48337			i = 0,
48338			p,
48339			value;
48340		(state.t._gsap || gsap$1.core.getCache(state.t)).uncache = 1;
48341  
48342		for (; i < l; i += 2) {
48343		  value = state[i + 1];
48344		  p = state[i];
48345  
48346		  if (value) {
48347			style[p] = value;
48348		  } else if (style[p]) {
48349			style.removeProperty(p.replace(_capsExp, "-$1").toLowerCase());
48350		  }
48351		}
48352	  }
48353	},
48354		_getState = function _getState(element) {
48355	  var l = _stateProps.length,
48356		  style = element.style,
48357		  state = [],
48358		  i = 0;
48359  
48360	  for (; i < l; i++) {
48361		state.push(_stateProps[i], style[_stateProps[i]]);
48362	  }
48363  
48364	  state.t = element;
48365	  return state;
48366	},
48367		_copyState = function _copyState(state, override, omitOffsets) {
48368	  var result = [],
48369		  l = state.length,
48370		  i = omitOffsets ? 8 : 0,
48371		  p;
48372  
48373	  for (; i < l; i += 2) {
48374		p = state[i];
48375		result.push(p, p in override ? override[p] : state[i + 1]);
48376	  }
48377  
48378	  result.t = state.t;
48379	  return result;
48380	},
48381		_winOffsets = {
48382	  left: 0,
48383	  top: 0
48384	},
48385		_parsePosition = function _parsePosition(value, trigger, scrollerSize, direction, scroll, marker, markerScroller, self, scrollerBounds, borderWidth, useFixedPosition, scrollerMax, containerAnimation, clampZeroProp) {
48386	  _isFunction(value) && (value = value(self));
48387  
48388	  if (_isString(value) && value.substr(0, 3) === "max") {
48389		value = scrollerMax + (value.charAt(4) === "=" ? _offsetToPx("0" + value.substr(3), scrollerSize) : 0);
48390	  }
48391  
48392	  var time = containerAnimation ? containerAnimation.time() : 0,
48393		  p1,
48394		  p2,
48395		  element;
48396	  containerAnimation && containerAnimation.seek(0);
48397	  isNaN(value) || (value = +value);
48398  
48399	  if (!_isNumber(value)) {
48400		_isFunction(trigger) && (trigger = trigger(self));
48401		var offsets = (value || "0").split(" "),
48402			bounds,
48403			localOffset,
48404			globalOffset,
48405			display;
48406		element = _getTarget(trigger, self) || _body$1;
48407		bounds = _getBounds(element) || {};
48408  
48409		if ((!bounds || !bounds.left && !bounds.top) && _getComputedStyle(element).display === "none") {
48410		  display = element.style.display;
48411		  element.style.display = "block";
48412		  bounds = _getBounds(element);
48413		  display ? element.style.display = display : element.style.removeProperty("display");
48414		}
48415  
48416		localOffset = _offsetToPx(offsets[0], bounds[direction.d]);
48417		globalOffset = _offsetToPx(offsets[1] || "0", scrollerSize);
48418		value = bounds[direction.p] - scrollerBounds[direction.p] - borderWidth + localOffset + scroll - globalOffset;
48419		markerScroller && _positionMarker(markerScroller, globalOffset, direction, scrollerSize - globalOffset < 20 || markerScroller._isStart && globalOffset > 20);
48420		scrollerSize -= scrollerSize - globalOffset;
48421	  } else {
48422		containerAnimation && (value = gsap$1.utils.mapRange(containerAnimation.scrollTrigger.start, containerAnimation.scrollTrigger.end, 0, scrollerMa
vendor: 4,541 bytes, lines 48422-48578
48422x, value));
48423		markerScroller && _positionMarker(markerScroller, scrollerSize, direction, true);
48424	  }
48425  
48426	  if (clampZeroProp) {
48427		self[clampZeroProp] = value || -0.001;
48428		value < 0 && (value = 0);
48429	  }
48430  
48431	  if (marker) {
48432		var position = value + scrollerSize,
48433			isStart = marker._isStart;
48434		p1 = "scroll" + direction.d2;
48435  
48436		_positionMarker(marker, position, direction, isStart && position > 20 || !isStart && (useFixedPosition ? Math.max(_body$1[p1], _docEl$1[p1]) : marker.parentNode[p1]) <= position + 1);
48437  
48438		if (useFixedPosition) {
48439		  scrollerBounds = _getBounds(markerScroller);
48440		  useFixedPosition && (marker.style[direction.op.p] = scrollerBounds[direction.op.p] - direction.op.m - marker._offset + _px);
48441		}
48442	  }
48443  
48444	  if (containerAnimation && element) {
48445		p1 = _getBounds(element);
48446		containerAnimation.seek(scrollerMax);
48447		p2 = _getBounds(element);
48448		containerAnimation._caScrollDist = p1[direction.p] - p2[direction.p];
48449		value = value / containerAnimation._caScrollDist * scrollerMax;
48450	  }
48451  
48452	  containerAnimation && containerAnimation.seek(time);
48453	  return containerAnimation ? value : Math.round(value);
48454	},
48455		_prefixExp = /(webkit|moz|length|cssText|inset)/i,
48456		_reparent = function _reparent(element, parent, top, left) {
48457	  if (element.parentNode !== parent) {
48458		var style = element.style,
48459			p,
48460			cs;
48461  
48462		if (parent === _body$1) {
48463		  element._stOrig = style.cssText;
48464		  cs = _getComputedStyle(element);
48465  
48466		  for (p in cs) {
48467			if (!+p && !_prefixExp.test(p) && cs[p] && typeof style[p] === "string" && p !== "0") {
48468			  style[p] = cs[p];
48469			}
48470		  }
48471  
48472		  style.top = top;
48473		  style.left = left;
48474		} else {
48475		  style.cssText = element._stOrig;
48476		}
48477  
48478		gsap$1.core.getCache(element).uncache = 1;
48479		parent.appendChild(element);
48480	  }
48481	},
48482		_interruptionTracker = function _interruptionTracker(getValueFunc, initialValue, onInterrupt) {
48483	  var last1 = initialValue,
48484		  last2 = last1;
48485	  return function (value) {
48486		var current = Math.round(getValueFunc());
48487  
48488		if (current !== last1 && current !== last2 && Math.abs(current - last1) > 3 && Math.abs(current - last2) > 3) {
48489		  value = current;
48490		  onInterrupt && onInterrupt();
48491		}
48492  
48493		last2 = last1;
48494		last1 = value;
48495		return value;
48496	  };
48497	},
48498		_shiftMarker = function _shiftMarker(marker, direction, value) {
48499	  var vars = {};
48500	  vars[direction.p] = "+=" + value;
48501	  gsap$1.set(marker, vars);
48502	},
48503		_getTweenCreator = function _getTweenCreator(scroller, direction) {
48504	  var getScroll = _getScrollFunc(scroller, direction),
48505		  prop = "_scroll" + direction.p2,
48506		  getTween = function getTween(scrollTo, vars, initialValue, change1, change2) {
48507		var tween = getTween.tween,
48508			onComplete = vars.onComplete,
48509			modifiers = {};
48510		initialValue = initialValue || getScroll();
48511  
48512		var checkForInterruption = _interruptionTracker(getScroll, initialValue, function () {
48513		  tween.kill();
48514		  getTween.tween = 0;
48515		});
48516  
48517		change2 = change1 && change2 || 0;
48518		change1 = change1 || scrollTo - initialValue;
48519		tween && tween.kill();
48520		vars[prop] = scrollTo;
48521		vars.inherit = false;
48522		vars.modifiers = modifiers;
48523  
48524		modifiers[prop] = function () {
48525		  return checkForInterruption(initialValue + change1 * tween.ratio + change2 * tween.ratio * tween.ratio);
48526		};
48527  
48528		vars.onUpdate = function () {
48529		  _scrollers.cache++;
48530		  getTween.tween && _updateAll();
48531		};
48532  
48533		vars.onComplete = function () {
48534		  getTween.tween = 0;
48535		  onComplete && onComplete.call(tween);
48536		};
48537  
48538		tween = getTween.tween = gsap$1.to(scroller, vars);
48539		return tween;
48540	  };
48541  
48542	  scroller[prop] = getScroll;
48543  
48544	  getScroll.wheelHandler = function () {
48545		return getTween.tween && getTween.tween.kill() && (getTween.tween = 0);
48546	  };
48547  
48548	  _addListener$1(scroller, "wheel", getScroll.wheelHandler);
48549  
48550	  ScrollTrigger$1.isTouch && _addListener$1(scroller, "touchmove", getScroll.wheelHandler);
48551	  return getTween;
48552	};
48553  
48554	var ScrollTrigger$1 = function () {
48555	  function ScrollTrigger(vars, animation) {
48556		_coreInitted$1 || ScrollTrigger.register(gsap$1) || console.warn("Please gsap.registerPlugin(ScrollTrigger)");
48557  
48558		_context$1(this);
48559  
48560		this.init(vars, animation);
48561	  }
48562  
48563	  var _proto = ScrollTrigger.prototype;
48564  
48565	  _proto.init = function init(vars, animation) {
48566		this.progress = this.start = 0;
48567		this.vars && this.kill(true, true);
48568  
48569		if (!_enabled) {
48570		  this.update = this.refresh = this.kill = _passThrough;
48571		  return;
48572		}
48573  
48574		vars = _setDefaults(_isString(vars) || _isNumber(vars) || vars.nodeType ? {
48575		  trigger: vars
48576		} : vars, _defaults);
48577  
48578		var _vars = vars,
vendor: 4,184 bytes, lines 48579-48719
48579			onUpdate = _vars.onUpdate,
48580			toggleClass = _vars.toggleClass,
48581			id = _vars.id,
48582			onToggle = _vars.onToggle,
48583			onRefresh = _vars.onRefresh,
48584			scrub = _vars.scrub,
48585			trigger = _vars.trigger,
48586			pin = _vars.pin,
48587			pinSpacing = _vars.pinSpacing,
48588			invalidateOnRefresh = _vars.invalidateOnRefresh,
48589			anticipatePin = _vars.anticipatePin,
48590			onScrubComplete = _vars.onScrubComplete,
48591			onSnapComplete = _vars.onSnapComplete,
48592			once = _vars.once,
48593			snap = _vars.snap,
48594			pinReparent = _vars.pinReparent,
48595			pinSpacer = _vars.pinSpacer,
48596			containerAnimation = _vars.containerAnimation,
48597			fastScrollEnd = _vars.fastScrollEnd,
48598			preventOverlaps = _vars.preventOverlaps,
48599			direction = vars.horizontal || vars.containerAnimation && vars.horizontal !== false ? _horizontal : _vertical,
48600			isToggle = !scrub && scrub !== 0,
48601			scroller = _getTarget(vars.scroller || _win$1),
48602			scrollerCache = gsap$1.core.getCache(scroller),
48603			isViewport = _isViewport$1(scroller),
48604			useFixedPosition = ("pinType" in vars ? vars.pinType : _getProxyProp(scroller, "pinType") || isViewport && "fixed") === "fixed",
48605			callbacks = [vars.onEnter, vars.onLeave, vars.onEnterBack, vars.onLeaveBack],
48606			toggleActions = isToggle && vars.toggleActions.split(" "),
48607			markers = "markers" in vars ? vars.markers : _defaults.markers,
48608			borderWidth = isViewport ? 0 : parseFloat(_getComputedStyle(scroller)["border" + direction.p2 + _Width]) || 0,
48609			self = this,
48610			onRefreshInit = vars.onRefreshInit && function () {
48611		  return vars.onRefreshInit(self);
48612		},
48613			getScrollerSize = _getSizeFunc(scroller, isViewport, direction),
48614			getScrollerOffsets = _getOffsetsFunc(scroller, isViewport),
48615			lastSnap = 0,
48616			lastRefresh = 0,
48617			prevProgress = 0,
48618			scrollFunc = _getScrollFunc(scroller, direction),
48619			tweenTo,
48620			pinCache,
48621			snapFunc,
48622			scroll1,
48623			scroll2,
48624			start,
48625			end,
48626			markerStart,
48627			markerEnd,
48628			markerStartTrigger,
48629			markerEndTrigger,
48630			markerVars,
48631			executingOnRefresh,
48632			change,
48633			pinOriginalState,
48634			pinActiveState,
48635			pinState,
48636			spacer,
48637			offset,
48638			pinGetter,
48639			pinSetter,
48640			pinStart,
48641			pinChange,
48642			spacingStart,
48643			spacerState,
48644			markerStartSetter,
48645			pinMoves,
48646			markerEndSetter,
48647			cs,
48648			snap1,
48649			snap2,
48650			scrubTween,
48651			scrubSmooth,
48652			snapDurClamp,
48653			snapDelayedCall,
48654			prevScroll,
48655			prevAnimProgress,
48656			caMarkerSetter,
48657			customRevertReturn;
48658  
48659		self._startClamp = self._endClamp = false;
48660		self._dir = direction;
48661		anticipatePin *= 45;
48662		self.scroller = scroller;
48663		self.scroll = containerAnimation ? containerAnimation.time.bind(containerAnimation) : scrollFunc;
48664		scroll1 = scrollFunc();
48665		self.vars = vars;
48666		animation = animation || vars.animation;
48667  
48668		if ("refreshPriority" in vars) {
48669		  _sort = 1;
48670		  vars.refreshPriority === -9999 && (_primary = self);
48671		}
48672  
48673		scrollerCache.tweenScroll = scrollerCache.tweenScroll || {
48674		  top: _getTweenCreator(scroller, _vertical),
48675		  left: _getTweenCreator(scroller, _horizontal)
48676		};
48677		self.tweenTo = tweenTo = scrollerCache.tweenScroll[direction.p];
48678  
48679		self.scrubDuration = function (value) {
48680		  scrubSmooth = _isNumber(value) && value;
48681  
48682		  if (!scrubSmooth) {
48683			scrubTween && scrubTween.progress(1).kill();
48684			scrubTween = 0;
48685		  } else {
48686			scrubTween ? scrubTween.duration(value) : scrubTween = gsap$1.to(animation, {
48687			  ease: "expo",
48688			  totalProgress: "+=0",
48689			  inherit: false,
48690			  duration: scrubSmooth,
48691			  paused: true,
48692			  onComplete: function onComplete() {
48693				return onScrubComplete && onScrubComplete(self);
48694			  }
48695			});
48696		  }
48697		};
48698  
48699		if (animation) {
48700		  animation.vars.lazy = false;
48701		  animation._initted && !self.isReverted || animation.vars.immediateRender !== false && vars.immediateRender !== false && animation.duration() && animation.render(0, true, true);
48702		  self.animation = animation.pause();
48703		  animation.scrollTrigger = self;
48704		  self.scrubDuration(scrub);
48705		  snap1 = 0;
48706		  id || (id = animation.vars.id);
48707		}
48708  
48709		if (snap) {
48710		  if (!_isObject(snap) || snap.push) {
48711			snap = {
48712			  snapTo: snap
48713			};
48714		  }
48715  
48716		  "scrollBehavior" in _body$1.style && gsap$1.set(isViewport ? [_body$1, _docEl$1] : scroller, {
48717			scrollBehavior: "auto"
48718		  });
48719  
vendor: 4,259 bytes, lines 48720-48815
48720		  _scrollers.forEach(function (o) {
48721			return _isFunction(o) && o.target === (isViewport ? _doc$1.scrollingElement || _docEl$1 : scroller) && (o.smooth = false);
48722		  });
48723  
48724		  snapFunc = _isFunction(snap.snapTo) ? snap.snapTo : snap.snapTo === "labels" ? _getClosestLabel(animation) : snap.snapTo === "labelsDirectional" ? _getLabelAtDirection(animation) : snap.directional !== false ? function (value, st) {
48725			return _snapDirectional(snap.snapTo)(value, _getTime$1() - lastRefresh < 500 ? 0 : st.direction);
48726		  } : gsap$1.utils.snap(snap.snapTo);
48727		  snapDurClamp = snap.duration || {
48728			min: 0.1,
48729			max: 2
48730		  };
48731		  snapDurClamp = _isObject(snapDurClamp) ? _clamp$1(snapDurClamp.min, snapDurClamp.max) : _clamp$1(snapDurClamp, snapDurClamp);
48732		  snapDelayedCall = gsap$1.delayedCall(snap.delay || scrubSmooth / 2 || 0.1, function () {
48733			var scroll = scrollFunc(),
48734				refreshedRecently = _getTime$1() - lastRefresh < 500,
48735				tween = tweenTo.tween;
48736  
48737			if ((refreshedRecently || Math.abs(self.getVelocity()) < 10) && !tween && !_pointerIsDown && lastSnap !== scroll) {
48738			  var progress = (scroll - start) / change,
48739				  totalProgress = animation && !isToggle ? animation.totalProgress() : progress,
48740				  velocity = refreshedRecently ? 0 : (totalProgress - snap2) / (_getTime$1() - _time2) * 1000 || 0,
48741				  change1 = gsap$1.utils.clamp(-progress, 1 - progress, _abs(velocity / 2) * velocity / 0.185),
48742				  naturalEnd = progress + (snap.inertia === false ? 0 : change1),
48743				  endValue,
48744				  endScroll,
48745				  _snap = snap,
48746				  onStart = _snap.onStart,
48747				  _onInterrupt = _snap.onInterrupt,
48748				  _onComplete = _snap.onComplete;
48749			  endValue = snapFunc(naturalEnd, self);
48750			  _isNumber(endValue) || (endValue = naturalEnd);
48751			  endScroll = Math.round(start + endValue * change);
48752  
48753			  if (scroll <= end && scroll >= start && endScroll !== scroll) {
48754				if (tween && !tween._initted && tween.data <= _abs(endScroll - scroll)) {
48755				  return;
48756				}
48757  
48758				if (snap.inertia === false) {
48759				  change1 = endValue - progress;
48760				}
48761  
48762				tweenTo(endScroll, {
48763				  duration: snapDurClamp(_abs(Math.max(_abs(naturalEnd - totalProgress), _abs(endValue - totalProgress)) * 0.185 / velocity / 0.05 || 0)),
48764				  ease: snap.ease || "power3",
48765				  data: _abs(endScroll - scroll),
48766				  onInterrupt: function onInterrupt() {
48767					return snapDelayedCall.restart(true) && _onInterrupt && _onInterrupt(self);
48768				  },
48769				  onComplete: function onComplete() {
48770					self.update();
48771					lastSnap = scrollFunc();
48772  
48773					if (animation) {
48774					  scrubTween ? scrubTween.resetTo("totalProgress", endValue, animation._tTime / animation._tDur) : animation.progress(endValue);
48775					}
48776  
48777					snap1 = snap2 = animation && !isToggle ? animation.totalProgress() : self.progress;
48778					onSnapComplete && onSnapComplete(self);
48779					_onComplete && _onComplete(self);
48780				  }
48781				}, scroll, change1 * change, endScroll - scroll - change1 * change);
48782				onStart && onStart(self, tweenTo.tween);
48783			  }
48784			} else if (self.isActive && lastSnap !== scroll) {
48785			  snapDelayedCall.restart(true);
48786			}
48787		  }).pause();
48788		}
48789  
48790		id && (_ids[id] = self);
48791		trigger = self.trigger = _getTarget(trigger || pin !== true && pin);
48792		customRevertReturn = trigger && trigger._gsap && trigger._gsap.stRevert;
48793		customRevertReturn && (customRevertReturn = customRevertReturn(self));
48794		pin = pin === true ? trigger : _getTarget(pin);
48795		_isString(toggleClass) && (toggleClass = {
48796		  targets: trigger,
48797		  className: toggleClass
48798		});
48799  
48800		if (pin) {
48801		  pinSpacing === false || pinSpacing === _margin || (pinSpacing = !pinSpacing && pin.parentNode && pin.parentNode.style && _getComputedStyle(pin.parentNode).display === "flex" ? false : _padding);
48802		  self.pin = pin;
48803		  pinCache = gsap$1.core.getCache(pin);
48804  
48805		  if (!pinCache.spacer) {
48806			if (pinSpacer) {
48807			  pinSpacer = _getTarget(pinSpacer);
48808			  pinSpacer && !pinSpacer.nodeType && (pinSpacer = pinSpacer.current || pinSpacer.nativeElement);
48809			  pinCache.spacerIsNative = !!pinSpacer;
48810			  pinSpacer && (pinCache.spacerState = _getState(pinSpacer));
48811			}
48812  
48813			pinCache.spacer = spacer = pinSpacer || _doc$1.createElement("div");
48814			spacer.classList.add("pin-spacer");
48815			id && spacer.classList.add("pin-spacer-" + id);
vendor: 4,987 bytes, lines 48816-48970
48816			pinCache.pinState = pinOriginalState = _getState(pin);
48817		  } else {
48818			pinOriginalState = pinCache.pinState;
48819		  }
48820  
48821		  vars.force3D !== false && gsap$1.set(pin, {
48822			force3D: true
48823		  });
48824		  self.spacer = spacer = pinCache.spacer;
48825		  cs = _getComputedStyle(pin);
48826		  spacingStart = cs[pinSpacing + direction.os2];
48827		  pinGetter = gsap$1.getProperty(pin);
48828		  pinSetter = gsap$1.quickSetter(pin, direction.a, _px);
48829  
48830		  _swapPinIn(pin, spacer, cs);
48831  
48832		  pinState = _getState(pin);
48833		}
48834  
48835		if (markers) {
48836		  markerVars = _isObject(markers) ? _setDefaults(markers, _markerDefaults) : _markerDefaults;
48837		  markerStartTrigger = _createMarker("scroller-start", id, scroller, direction, markerVars, 0);
48838		  markerEndTrigger = _createMarker("scroller-end", id, scroller, direction, markerVars, 0, markerStartTrigger);
48839		  offset = markerStartTrigger["offset" + direction.op.d2];
48840  
48841		  var content = _getTarget(_getProxyProp(scroller, "content") || scroller);
48842  
48843		  markerStart = this.markerStart = _createMarker("start", id, content, direction, markerVars, offset, 0, containerAnimation);
48844		  markerEnd = this.markerEnd = _createMarker("end", id, content, direction, markerVars, offset, 0, containerAnimation);
48845		  containerAnimation && (caMarkerSetter = gsap$1.quickSetter([markerStart, markerEnd], direction.a, _px));
48846  
48847		  if (!useFixedPosition && !(_proxies.length && _getProxyProp(scroller, "fixedMarkers") === true)) {
48848			_makePositionable(isViewport ? _body$1 : scroller);
48849  
48850			gsap$1.set([markerStartTrigger, markerEndTrigger], {
48851			  force3D: true
48852			});
48853			markerStartSetter = gsap$1.quickSetter(markerStartTrigger, direction.a, _px);
48854			markerEndSetter = gsap$1.quickSetter(markerEndTrigger, direction.a, _px);
48855		  }
48856		}
48857  
48858		if (containerAnimation) {
48859		  var oldOnUpdate = containerAnimation.vars.onUpdate,
48860			  oldParams = containerAnimation.vars.onUpdateParams;
48861		  containerAnimation.eventCallback("onUpdate", function () {
48862			self.update(0, 0, 1);
48863			oldOnUpdate && oldOnUpdate.apply(containerAnimation, oldParams || []);
48864		  });
48865		}
48866  
48867		self.previous = function () {
48868		  return _triggers[_triggers.indexOf(self) - 1];
48869		};
48870  
48871		self.next = function () {
48872		  return _triggers[_triggers.indexOf(self) + 1];
48873		};
48874  
48875		self.revert = function (revert, temp) {
48876		  if (!temp) {
48877			return self.kill(true);
48878		  }
48879  
48880		  var r = revert !== false || !self.enabled,
48881			  prevRefreshing = _refreshing;
48882  
48883		  if (r !== self.isReverted) {
48884			if (r) {
48885			  prevScroll = Math.max(scrollFunc(), self.scroll.rec || 0);
48886			  prevProgress = self.progress;
48887			  prevAnimProgress = animation && animation.progress();
48888			}
48889  
48890			markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) {
48891			  return m.style.display = r ? "none" : "block";
48892			});
48893  
48894			if (r) {
48895			  _refreshing = self;
48896			  self.update(r);
48897			}
48898  
48899			if (pin && (!pinReparent || !self.isActive)) {
48900			  if (r) {
48901				_swapPinOut(pin, spacer, pinOriginalState);
48902			  } else {
48903				_swapPinIn(pin, spacer, _getComputedStyle(pin), spacerState);
48904			  }
48905			}
48906  
48907			r || self.update(r);
48908			_refreshing = prevRefreshing;
48909			self.isReverted = r;
48910		  }
48911		};
48912  
48913		self.refresh = function (soft, force, position, pinOffset) {
48914		  if ((_refreshing || !self.enabled) && !force) {
48915			return;
48916		  }
48917  
48918		  if (pin && soft && _lastScrollTime) {
48919			_addListener$1(ScrollTrigger, "scrollEnd", _softRefresh);
48920  
48921			return;
48922		  }
48923  
48924		  !_refreshingAll && onRefreshInit && onRefreshInit(self);
48925		  _refreshing = self;
48926  
48927		  if (tweenTo.tween && !position) {
48928			tweenTo.tween.kill();
48929			tweenTo.tween = 0;
48930		  }
48931  
48932		  scrubTween && scrubTween.pause();
48933		  invalidateOnRefresh && animation && animation.revert({
48934			kill: false
48935		  }).invalidate();
48936		  self.isReverted || self.revert(true, true);
48937		  self._subPinOffset = false;
48938  
48939		  var size = getScrollerSize(),
48940			  scrollerBounds = getScrollerOffsets(),
48941			  max = containerAnimation ? containerAnimation.duration() : _maxScroll(scroller, direction),
48942			  isFirstRefresh = change <= 0.01,
48943			  offset = 0,
48944			  otherPinOffset = pinOffset || 0,
48945			  parsedEnd = _isObject(position) ? position.end : vars.end,
48946			  parsedEndTrigger = vars.endTrigger || trigger,
48947			  parsedStart = _isObject(position) ? position.start : vars.start || (vars.start === 0 || !trigger ? 0 : pin ? "0 0" : "0 100%"),
48948			  pinnedContainer = self.pinnedContainer = vars.pinnedContainer && _getTarget(vars.pinnedContainer, self),
48949			  triggerIndex = trigger && Math.max(0, _triggers.indexOf(self)) || 0,
48950			  i = triggerIndex,
48951			  cs,
48952			  bounds,
48953			  scroll,
48954			  isVertical,
48955			  override,
48956			  curTrigger,
48957			  curPin,
48958			  oppositeScroll,
48959			  initted,
48960			  revertedPins,
48961			  forcedOverflow,
48962			  markerStartOffset,
48963			  markerEndOffset;
48964  
48965		  if (markers && _isObject(position)) {
48966			markerStartOffset = gsap$1.getProperty(markerStartTrigger, direction.p);
48967			markerEndOffset = gsap$1.getProperty(markerEndTrigger, direction.p);
48968		  }
48969  
48970		  while (i--) {
vendor: 4,360 bytes, lines 48971-49082
48971			curTrigger = _triggers[i];
48972			curTrigger.end || curTrigger.refresh(0, 1) || (_refreshing = self);
48973			curPin = curTrigger.pin;
48974  
48975			if (curPin && (curPin === trigger || curPin === pin || curPin === pinnedContainer) && !curTrigger.isReverted) {
48976			  revertedPins || (revertedPins = []);
48977			  revertedPins.unshift(curTrigger);
48978			  curTrigger.revert(true, true);
48979			}
48980  
48981			if (curTrigger !== _triggers[i]) {
48982			  triggerIndex--;
48983			  i--;
48984			}
48985		  }
48986  
48987		  _isFunction(parsedStart) && (parsedStart = parsedStart(self));
48988		  parsedStart = _parseClamp(parsedStart, "start", self);
48989		  start = _parsePosition(parsedStart, trigger, size, direction, scrollFunc(), markerStart, markerStartTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation, self._startClamp && "_startClamp") || (pin ? -0.001 : 0);
48990		  _isFunction(parsedEnd) && (parsedEnd = parsedEnd(self));
48991  
48992		  if (_isString(parsedEnd) && !parsedEnd.indexOf("+=")) {
48993			if (~parsedEnd.indexOf(" ")) {
48994			  parsedEnd = (_isString(parsedStart) ? parsedStart.split(" ")[0] : "") + parsedEnd;
48995			} else {
48996			  offset = _offsetToPx(parsedEnd.substr(2), size);
48997			  parsedEnd = _isString(parsedStart) ? parsedStart : (containerAnimation ? gsap$1.utils.mapRange(0, containerAnimation.duration(), containerAnimation.scrollTrigger.start, containerAnimation.scrollTrigger.end, start) : start) + offset;
48998			  parsedEndTrigger = trigger;
48999			}
49000		  }
49001  
49002		  parsedEnd = _parseClamp(parsedEnd, "end", self);
49003		  end = Math.max(start, _parsePosition(parsedEnd || (parsedEndTrigger ? "100% 0" : max), parsedEndTrigger, size, direction, scrollFunc() + offset, markerEnd, markerEndTrigger, self, scrollerBounds, borderWidth, useFixedPosition, max, containerAnimation, self._endClamp && "_endClamp")) || -0.001;
49004		  offset = 0;
49005		  i = triggerIndex;
49006  
49007		  while (i--) {
49008			curTrigger = _triggers[i];
49009			curPin = curTrigger.pin;
49010  
49011			if (curPin && curTrigger.start - curTrigger._pinPush <= start && !containerAnimation && curTrigger.end > 0) {
49012			  cs = curTrigger.end - (self._startClamp ? Math.max(0, curTrigger.start) : curTrigger.start);
49013  
49014			  if ((curPin === trigger && curTrigger.start - curTrigger._pinPush < start || curPin === pinnedContainer) && isNaN(parsedStart)) {
49015				offset += cs * (1 - curTrigger.progress);
49016			  }
49017  
49018			  curPin === pin && (otherPinOffset += cs);
49019			}
49020		  }
49021  
49022		  start += offset;
49023		  end += offset;
49024		  self._startClamp && (self._startClamp += offset);
49025  
49026		  if (self._endClamp && !_refreshingAll) {
49027			self._endClamp = end || -0.001;
49028			end = Math.min(end, _maxScroll(scroller, direction));
49029		  }
49030  
49031		  change = end - start || (start -= 0.01) && 0.001;
49032  
49033		  if (isFirstRefresh) {
49034			prevProgress = gsap$1.utils.clamp(0, 1, gsap$1.utils.normalize(start, end, prevScroll));
49035		  }
49036  
49037		  self._pinPush = otherPinOffset;
49038  
49039		  if (markerStart && offset) {
49040			cs = {};
49041			cs[direction.a] = "+=" + offset;
49042			pinnedContainer && (cs[direction.p] = "-=" + scrollFunc());
49043			gsap$1.set([markerStart, markerEnd], cs);
49044		  }
49045  
49046		  if (pin && !(_clampingMax && self.end >= _maxScroll(scroller, direction))) {
49047			cs = _getComputedStyle(pin);
49048			isVertical = direction === _vertical;
49049			scroll = scrollFunc();
49050			pinStart = parseFloat(pinGetter(direction.a)) + otherPinOffset;
49051  
49052			if (!max && end > 1) {
49053			  forcedOverflow = (isViewport ? _doc$1.scrollingElement || _docEl$1 : scroller).style;
49054			  forcedOverflow = {
49055				style: forcedOverflow,
49056				value: forcedOverflow["overflow" + direction.a.toUpperCase()]
49057			  };
49058  
49059			  if (isViewport && _getComputedStyle(_body$1)["overflow" + direction.a.toUpperCase()] !== "scroll") {
49060				forcedOverflow.style["overflow" + direction.a.toUpperCase()] = "scroll";
49061			  }
49062			}
49063  
49064			_swapPinIn(pin, spacer, cs);
49065  
49066			pinState = _getState(pin);
49067			bounds = _getBounds(pin, true);
49068			oppositeScroll = useFixedPosition && _getScrollFunc(scroller, isVertical ? _horizontal : _vertical)();
49069  
49070			if (pinSpacing) {
49071			  spacerState = [pinSpacing + direction.os2, change + otherPinOffset + _px];
49072			  spacerState.t = spacer;
49073			  i = pinSpacing === _padding ? _getSize(pin, direction) + change + otherPinOffset : 0;
49074  
49075			  if (i) {
49076				spacerState.push(direction.d, i + _px);
49077				spacer.style.flexBasis !== "auto" && (spacer.style.flexBasis = i + _px);
49078			  }
49079  
49080			  _setState(spacerState);
49081  
49082			  if (pinnedContainer) {
vendor: 9,034 bytes, lines 49083-49325
49083				_triggers.forEach(function (t) {
49084				  if (t.pin === pinnedContainer && t.vars.pinSpacing !== false) {
49085					t._subPinOffset = true;
49086				  }
49087				});
49088			  }
49089  
49090			  useFixedPosition && scrollFunc(prevScroll);
49091			} else {
49092			  i = _getSize(pin, direction);
49093			  i && spacer.style.flexBasis !== "auto" && (spacer.style.flexBasis = i + _px);
49094			}
49095  
49096			if (useFixedPosition) {
49097			  override = {
49098				top: bounds.top + (isVertical ? scroll - start : oppositeScroll) + _px,
49099				left: bounds.left + (isVertical ? oppositeScroll : scroll - start) + _px,
49100				boxSizing: "border-box",
49101				position: "fixed"
49102			  };
49103			  override[_width] = override["max" + _Width] = Math.ceil(bounds.width) + _px;
49104			  override[_height] = override["max" + _Height] = Math.ceil(bounds.height) + _px;
49105			  override[_margin] = override[_margin + _Top] = override[_margin + _Right] = override[_margin + _Bottom] = override[_margin + _Left] = "0";
49106			  override[_padding] = cs[_padding];
49107			  override[_padding + _Top] = cs[_padding + _Top];
49108			  override[_padding + _Right] = cs[_padding + _Right];
49109			  override[_padding + _Bottom] = cs[_padding + _Bottom];
49110			  override[_padding + _Left] = cs[_padding + _Left];
49111			  pinActiveState = _copyState(pinOriginalState, override, pinReparent);
49112			  _refreshingAll && scrollFunc(0);
49113			}
49114  
49115			if (animation) {
49116			  initted = animation._initted;
49117  
49118			  _suppressOverwrites(1);
49119  
49120			  animation.render(animation.duration(), true, true);
49121			  pinChange = pinGetter(direction.a) - pinStart + change + otherPinOffset;
49122			  pinMoves = Math.abs(change - pinChange) > 1;
49123			  useFixedPosition && pinMoves && pinActiveState.splice(pinActiveState.length - 2, 2);
49124			  animation.render(0, true, true);
49125			  initted || animation.invalidate(true);
49126			  animation.parent || animation.totalTime(animation.totalTime());
49127  
49128			  _suppressOverwrites(0);
49129			} else {
49130			  pinChange = change;
49131			}
49132  
49133			forcedOverflow && (forcedOverflow.value ? forcedOverflow.style["overflow" + direction.a.toUpperCase()] = forcedOverflow.value : forcedOverflow.style.removeProperty("overflow-" + direction.a));
49134		  } else if (trigger && scrollFunc() && !containerAnimation) {
49135			bounds = trigger.parentNode;
49136  
49137			while (bounds && bounds !== _body$1) {
49138			  if (bounds._pinOffset) {
49139				start -= bounds._pinOffset;
49140				end -= bounds._pinOffset;
49141			  }
49142  
49143			  bounds = bounds.parentNode;
49144			}
49145		  }
49146  
49147		  revertedPins && revertedPins.forEach(function (t) {
49148			return t.revert(false, true);
49149		  });
49150		  self.start = start;
49151		  self.end = end;
49152		  scroll1 = scroll2 = _refreshingAll ? prevScroll : scrollFunc();
49153  
49154		  if (!containerAnimation && !_refreshingAll) {
49155			scroll1 < prevScroll && scrollFunc(prevScroll);
49156			self.scroll.rec = 0;
49157		  }
49158  
49159		  self.revert(false, true);
49160		  lastRefresh = _getTime$1();
49161  
49162		  if (snapDelayedCall) {
49163			lastSnap = -1;
49164			snapDelayedCall.restart(true);
49165		  }
49166  
49167		  _refreshing = 0;
49168		  animation && isToggle && (animation._initted || prevAnimProgress) && animation.progress() !== prevAnimProgress && animation.progress(prevAnimProgress || 0, true).render(animation.time(), true, true);
49169  
49170		  if (isFirstRefresh || prevProgress !== self.progress || containerAnimation || invalidateOnRefresh) {
49171			animation && !isToggle && animation.totalProgress(containerAnimation && start < -0.001 && !prevProgress ? gsap$1.utils.normalize(start, end, 0) : prevProgress, true);
49172			self.progress = isFirstRefresh || (scroll1 - start) / change === prevProgress ? 0 : prevProgress;
49173		  }
49174  
49175		  pin && pinSpacing && (spacer._pinOffset = Math.round(self.progress * pinChange));
49176		  scrubTween && scrubTween.invalidate();
49177  
49178		  if (!isNaN(markerStartOffset)) {
49179			markerStartOffset -= gsap$1.getProperty(markerStartTrigger, direction.p);
49180			markerEndOffset -= gsap$1.getProperty(markerEndTrigger, direction.p);
49181  
49182			_shiftMarker(markerStartTrigger, direction, markerStartOffset);
49183  
49184			_shiftMarker(markerStart, direction, markerStartOffset - (pinOffset || 0));
49185  
49186			_shiftMarker(markerEndTrigger, direction, markerEndOffset);
49187  
49188			_shiftMarker(markerEnd, direction, markerEndOffset - (pinOffset || 0));
49189		  }
49190  
49191		  isFirstRefresh && !_refreshingAll && self.update();
49192  
49193		  if (onRefresh && !_refreshingAll && !executingOnRefresh) {
49194			executingOnRefresh = true;
49195			onRefresh(self);
49196			executingOnRefresh = false;
49197		  }
49198		};
49199  
49200		self.getVelocity = function () {
49201		  return (scrollFunc() - scroll2) / (_getTime$1() - _time2) * 1000 || 0;
49202		};
49203  
49204		self.endAnimation = function () {
49205		  _endAnimation(self.callbackAnimation);
49206  
49207		  if (animation) {
49208			scrubTween ? scrubTween.progress(1) : !animation.paused() ? _endAnimation(animation, animation.reversed()) : isToggle || _endAnimation(animation, self.direction < 0, 1);
49209		  }
49210		};
49211  
49212		self.labelToScroll = function (label) {
49213		  return animation && animation.labels && (start || self.refresh() || start) + animation.labels[label] / animation.duration() * change || 0;
49214		};
49215  
49216		self.getTrailing = function (name) {
49217		  var i = _triggers.indexOf(self),
49218			  a = self.direction > 0 ? _triggers.slice(0, i).reverse() : _triggers.slice(i + 1);
49219  
49220		  return (_isString(name) ? a.filter(function (t) {
49221			return t.vars.preventOverlaps === name;
49222		  }) : a).filter(function (t) {
49223			return self.direction > 0 ? t.end <= start : t.start >= end;
49224		  });
49225		};
49226  
49227		self.update = function (reset, recordVelocity, forceFake) {
49228		  if (containerAnimation && !forceFake && !reset) {
49229			return;
49230		  }
49231  
49232		  var scroll = _refreshingAll === true ? prevScroll : self.scroll(),
49233			  p = reset ? 0 : (scroll - start) / change,
49234			  clipped = p < 0 ? 0 : p > 1 ? 1 : p || 0,
49235			  prevProgress = self.progress,
49236			  isActive,
49237			  wasActive,
49238			  toggleState,
49239			  action,
49240			  stateChanged,
49241			  toggled,
49242			  isAtMax,
49243			  isTakingAction;
49244  
49245		  if (recordVelocity) {
49246			scroll2 = scroll1;
49247			scroll1 = containerAnimation ? scrollFunc() : scroll;
49248  
49249			if (snap) {
49250			  snap2 = snap1;
49251			  snap1 = animation && !isToggle ? animation.totalProgress() : clipped;
49252			}
49253		  }
49254  
49255		  if (anticipatePin && pin && !_refreshing && !_startup$1 && _lastScrollTime) {
49256			if (!clipped && start < scroll + (scroll - scroll2) / (_getTime$1() - _time2) * anticipatePin) {
49257			  clipped = 0.0001;
49258			} else if (clipped === 1 && end > scroll + (scroll - scroll2) / (_getTime$1() - _time2) * anticipatePin) {
49259			  clipped = 0.9999;
49260			}
49261		  }
49262  
49263		  if (clipped !== prevProgress && self.enabled) {
49264			isActive = self.isActive = !!clipped && clipped < 1;
49265			wasActive = !!prevProgress && prevProgress < 1;
49266			toggled = isActive !== wasActive;
49267			stateChanged = toggled || !!clipped !== !!prevProgress;
49268			self.direction = clipped > prevProgress ? 1 : -1;
49269			self.progress = clipped;
49270  
49271			if (stateChanged && !_refreshing) {
49272			  toggleState = clipped && !prevProgress ? 0 : clipped === 1 ? 1 : prevProgress === 1 ? 2 : 3;
49273  
49274			  if (isToggle) {
49275				action = !toggled && toggleActions[toggleState + 1] !== "none" && toggleActions[toggleState + 1] || toggleActions[toggleState];
49276				isTakingAction = animation && (action === "complete" || action === "reset" || action in animation);
49277			  }
49278			}
49279  
49280			preventOverlaps && (toggled || isTakingAction) && (isTakingAction || scrub || !animation) && (_isFunction(preventOverlaps) ? preventOverlaps(self) : self.getTrailing(preventOverlaps).forEach(function (t) {
49281			  return t.endAnimation();
49282			}));
49283  
49284			if (!isToggle) {
49285			  if (scrubTween && !_refreshing && !_startup$1) {
49286				scrubTween._dp._time - scrubTween._start !== scrubTween._time && scrubTween.render(scrubTween._dp._time - scrubTween._start);
49287  
49288				if (scrubTween.resetTo) {
49289				  scrubTween.resetTo("totalProgress", clipped, animation._tTime / animation._tDur);
49290				} else {
49291				  scrubTween.vars.totalProgress = clipped;
49292				  scrubTween.invalidate().restart();
49293				}
49294			  } else if (animation) {
49295				animation.totalProgress(clipped, !!(_refreshing && (lastRefresh || reset)));
49296			  }
49297			}
49298  
49299			if (pin) {
49300			  reset && pinSpacing && (spacer.style[pinSpacing + direction.os2] = spacingStart);
49301  
49302			  if (!useFixedPosition) {
49303				pinSetter(_round(pinStart + pinChange * clipped));
49304			  } else if (stateChanged) {
49305				isAtMax = !reset && clipped > prevProgress && end + 1 > scroll && scroll + 1 >= _maxScroll(scroller, direction);
49306  
49307				if (pinReparent) {
49308				  if (!reset && (isActive || isAtMax)) {
49309					var bounds = _getBounds(pin, true),
49310						_offset = scroll - start;
49311  
49312					_reparent(pin, _body$1, bounds.top + (direction === _vertical ? _offset : 0) + _px, bounds.left + (direction === _vertical ? 0 : _offset) + _px);
49313				  } else {
49314					_reparent(pin, spacer);
49315				  }
49316				}
49317  
49318				_setState(isActive || isAtMax ? pinActiveState : pinState);
49319  
49320				pinMoves && clipped < 1 && isActive || pinSetter(pinStart + (clipped === 1 && !isAtMax ? pinChange : 0));
49321			  }
49322			}
49323  
49324			snap && !tweenTo.tween && !_refreshing && !_startup$1 && snapDelayedCall.restart(true);
49325			toggleClass && (toggled || once && clipped && (clipped < 1 || !_limitCallbacks)) && _toArray(toggleClass.targets).forEac
vendor: 4,284 bytes, lines 49325-49466
49325h(function (el) {
49326			  return el.classList[isActive || once ? "add" : "remove"](toggleClass.className);
49327			});
49328			onUpdate && !isToggle && !reset && onUpdate(self);
49329  
49330			if (stateChanged && !_refreshing) {
49331			  if (isToggle) {
49332				if (isTakingAction) {
49333				  if (action === "complete") {
49334					animation.pause().totalProgress(1);
49335				  } else if (action === "reset") {
49336					animation.restart(true).pause();
49337				  } else if (action === "restart") {
49338					animation.restart(true);
49339				  } else {
49340					animation[action]();
49341				  }
49342				}
49343  
49344				onUpdate && onUpdate(self);
49345			  }
49346  
49347			  if (toggled || !_limitCallbacks) {
49348				onToggle && toggled && _callback(self, onToggle);
49349				callbacks[toggleState] && _callback(self, callbacks[toggleState]);
49350				once && (clipped === 1 ? self.kill(false, 1) : callbacks[toggleState] = 0);
49351  
49352				if (!toggled) {
49353				  toggleState = clipped === 1 ? 1 : 3;
49354				  callbacks[toggleState] && _callback(self, callbacks[toggleState]);
49355				}
49356			  }
49357  
49358			  if (fastScrollEnd && !isActive && Math.abs(self.getVelocity()) > (_isNumber(fastScrollEnd) ? fastScrollEnd : 2500)) {
49359				_endAnimation(self.callbackAnimation);
49360  
49361				scrubTween ? scrubTween.progress(1) : _endAnimation(animation, action === "reverse" ? 1 : !clipped, 1);
49362			  }
49363			} else if (isToggle && onUpdate && !_refreshing) {
49364			  onUpdate(self);
49365			}
49366		  }
49367  
49368		  if (markerEndSetter) {
49369			var n = containerAnimation ? scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0) : scroll;
49370			markerStartSetter(n + (markerStartTrigger._isFlipped ? 1 : 0));
49371			markerEndSetter(n);
49372		  }
49373  
49374		  caMarkerSetter && caMarkerSetter(-scroll / containerAnimation.duration() * (containerAnimation._caScrollDist || 0));
49375		};
49376  
49377		self.enable = function (reset, refresh) {
49378		  if (!self.enabled) {
49379			self.enabled = true;
49380  
49381			_addListener$1(scroller, "resize", _onResize);
49382  
49383			isViewport || _addListener$1(scroller, "scroll", _onScroll$1);
49384			onRefreshInit && _addListener$1(ScrollTrigger, "refreshInit", onRefreshInit);
49385  
49386			if (reset !== false) {
49387			  self.progress = prevProgress = 0;
49388			  scroll1 = scroll2 = lastSnap = scrollFunc();
49389			}
49390  
49391			refresh !== false && self.refresh();
49392		  }
49393		};
49394  
49395		self.getTween = function (snap) {
49396		  return snap && tweenTo ? tweenTo.tween : scrubTween;
49397		};
49398  
49399		self.setPositions = function (newStart, newEnd, keepClamp, pinOffset) {
49400		  if (containerAnimation) {
49401			var st = containerAnimation.scrollTrigger,
49402				duration = containerAnimation.duration(),
49403				_change = st.end - st.start;
49404  
49405			newStart = st.start + _change * newStart / duration;
49406			newEnd = st.start + _change * newEnd / duration;
49407		  }
49408  
49409		  self.refresh(false, false, {
49410			start: _keepClamp(newStart, keepClamp && !!self._startClamp),
49411			end: _keepClamp(newEnd, keepClamp && !!self._endClamp)
49412		  }, pinOffset);
49413		  self.update();
49414		};
49415  
49416		self.adjustPinSpacing = function (amount) {
49417		  if (spacerState && amount) {
49418			var i = spacerState.indexOf(direction.d) + 1;
49419			spacerState[i] = parseFloat(spacerState[i]) + amount + _px;
49420			spacerState[1] = parseFloat(spacerState[1]) + amount + _px;
49421  
49422			_setState(spacerState);
49423		  }
49424		};
49425  
49426		self.disable = function (reset, allowAnimation) {
49427		  if (self.enabled) {
49428			reset !== false && self.revert(true, true);
49429			self.enabled = self.isActive = false;
49430			allowAnimation || scrubTween && scrubTween.pause();
49431			prevScroll = 0;
49432			pinCache && (pinCache.uncache = 1);
49433			onRefreshInit && _removeListener$1(ScrollTrigger, "refreshInit", onRefreshInit);
49434  
49435			if (snapDelayedCall) {
49436			  snapDelayedCall.pause();
49437			  tweenTo.tween && tweenTo.tween.kill() && (tweenTo.tween = 0);
49438			}
49439  
49440			if (!isViewport) {
49441			  var i = _triggers.length;
49442  
49443			  while (i--) {
49444				if (_triggers[i].scroller === scroller && _triggers[i] !== self) {
49445				  return;
49446				}
49447			  }
49448  
49449			  _removeListener$1(scroller, "resize", _onResize);
49450  
49451			  isViewport || _removeListener$1(scroller, "scroll", _onScroll$1);
49452			}
49453		  }
49454		};
49455  
49456		self.kill = function (revert, allowAnimation) {
49457		  self.disable(revert, allowAnimation);
49458		  scrubTween && !allowAnimation && scrubTween.kill();
49459		  id && delete _ids[id];
49460  
49461		  var i = _triggers.indexOf(self);
49462  
49463		  i >= 0 && _triggers.splice(i, 1);
49464		  i === _i && _direction > 0 && _i--;
49465		  i = 0;
49466  
vendor: 15,520 bytes, lines 49467-49973
49467		  _triggers.forEach(function (t) {
49468			return t.scroller === self.scroller && (i = 1);
49469		  });
49470  
49471		  i || _refreshingAll || (self.scroll.rec = 0);
49472  
49473		  if (animation) {
49474			animation.scrollTrigger = null;
49475			revert && animation.revert({
49476			  kill: false
49477			});
49478			allowAnimation || animation.kill();
49479		  }
49480  
49481		  markerStart && [markerStart, markerEnd, markerStartTrigger, markerEndTrigger].forEach(function (m) {
49482			return m.parentNode && m.parentNode.removeChild(m);
49483		  });
49484		  _primary === self && (_primary = 0);
49485  
49486		  if (pin) {
49487			pinCache && (pinCache.uncache = 1);
49488			i = 0;
49489  
49490			_triggers.forEach(function (t) {
49491			  return t.pin === pin && i++;
49492			});
49493  
49494			i || (pinCache.spacer = 0);
49495		  }
49496  
49497		  vars.onKill && vars.onKill(self);
49498		};
49499  
49500		_triggers.push(self);
49501  
49502		self.enable(false, false);
49503		customRevertReturn && customRevertReturn(self);
49504  
49505		if (animation && animation.add && !change) {
49506		  var updateFunc = self.update;
49507  
49508		  self.update = function () {
49509			self.update = updateFunc;
49510			start || end || self.refresh();
49511		  };
49512  
49513		  gsap$1.delayedCall(0.01, self.update);
49514		  change = 0.01;
49515		  start = end = 0;
49516		} else {
49517		  self.refresh();
49518		}
49519  
49520		pin && _queueRefreshAll();
49521	  };
49522  
49523	  ScrollTrigger.register = function register(core) {
49524		if (!_coreInitted$1) {
49525		  gsap$1 = core || _getGSAP$1();
49526		  _windowExists() && window.document && ScrollTrigger.enable();
49527		  _coreInitted$1 = _enabled;
49528		}
49529  
49530		return _coreInitted$1;
49531	  };
49532  
49533	  ScrollTrigger.defaults = function defaults(config) {
49534		if (config) {
49535		  for (var p in config) {
49536			_defaults[p] = config[p];
49537		  }
49538		}
49539  
49540		return _defaults;
49541	  };
49542  
49543	  ScrollTrigger.disable = function disable(reset, kill) {
49544		_enabled = 0;
49545  
49546		_triggers.forEach(function (trigger) {
49547		  return trigger[kill ? "kill" : "disable"](reset);
49548		});
49549  
49550		_removeListener$1(_win$1, "wheel", _onScroll$1);
49551  
49552		_removeListener$1(_doc$1, "scroll", _onScroll$1);
49553  
49554		clearInterval(_syncInterval);
49555  
49556		_removeListener$1(_doc$1, "touchcancel", _passThrough);
49557  
49558		_removeListener$1(_body$1, "touchstart", _passThrough);
49559  
49560		_multiListener(_removeListener$1, _doc$1, "pointerdown,touchstart,mousedown", _pointerDownHandler);
49561  
49562		_multiListener(_removeListener$1, _doc$1, "pointerup,touchend,mouseup", _pointerUpHandler);
49563  
49564		_resizeDelay.kill();
49565  
49566		_iterateAutoRefresh(_removeListener$1);
49567  
49568		for (var i = 0; i < _scrollers.length; i += 3) {
49569		  _wheelListener(_removeListener$1, _scrollers[i], _scrollers[i + 1]);
49570  
49571		  _wheelListener(_removeListener$1, _scrollers[i], _scrollers[i + 2]);
49572		}
49573	  };
49574  
49575	  ScrollTrigger.enable = function enable() {
49576		_win$1 = window;
49577		_doc$1 = document;
49578		_docEl$1 = _doc$1.documentElement;
49579		_body$1 = _doc$1.body;
49580  
49581		if (gsap$1) {
49582		  _toArray = gsap$1.utils.toArray;
49583		  _clamp$1 = gsap$1.utils.clamp;
49584		  _context$1 = gsap$1.core.context || _passThrough;
49585		  _suppressOverwrites = gsap$1.core.suppressOverwrites || _passThrough;
49586		  _scrollRestoration = _win$1.history.scrollRestoration || "auto";
49587		  _lastScroll = _win$1.pageYOffset;
49588		  gsap$1.core.globals("ScrollTrigger", ScrollTrigger);
49589  
49590		  if (_body$1) {
49591			_enabled = 1;
49592			_div100vh = document.createElement("div");
49593			_div100vh.style.height = "100vh";
49594			_div100vh.style.position = "absolute";
49595  
49596			_refresh100vh();
49597  
49598			_rafBugFix();
49599  
49600			Observer.register(gsap$1);
49601			ScrollTrigger.isTouch = Observer.isTouch;
49602			_fixIOSBug = Observer.isTouch && /(iPad|iPhone|iPod|Mac)/g.test(navigator.userAgent);
49603			_ignoreMobileResize = Observer.isTouch === 1;
49604  
49605			_addListener$1(_win$1, "wheel", _onScroll$1);
49606  
49607			_root$1 = [_win$1, _doc$1, _docEl$1, _body$1];
49608  
49609			if (gsap$1.matchMedia) {
49610			  ScrollTrigger.matchMedia = function (vars) {
49611				var mm = gsap$1.matchMedia(),
49612					p;
49613  
49614				for (p in vars) {
49615				  mm.add(p, vars[p]);
49616				}
49617  
49618				return mm;
49619			  };
49620  
49621			  gsap$1.addEventListener("matchMediaInit", function () {
49622				return _revertAll();
49623			  });
49624			  gsap$1.addEventListener("matchMediaRevert", function () {
49625				return _revertRecorded();
49626			  });
49627			  gsap$1.addEventListener("matchMedia", function () {
49628				_refreshAll(0, 1);
49629  
49630				_dispatch("matchMedia");
49631			  });
49632			  gsap$1.matchMedia("(orientation: portrait)", function () {
49633				_setBaseDimensions();
49634  
49635				return _setBaseDimensions;
49636			  });
49637			} else {
49638			  console.warn("Requires GSAP 3.11.0 or later");
49639			}
49640  
49641			_setBaseDimensions();
49642  
49643			_addListener$1(_doc$1, "scroll", _onScroll$1);
49644  
49645			var bodyStyle = _body$1.style,
49646				border = bodyStyle.borderTopStyle,
49647				AnimationProto = gsap$1.core.Animation.prototype,
49648				bounds,
49649				i;
49650			AnimationProto.revert || Object.defineProperty(AnimationProto, "revert", {
49651			  value: function value() {
49652				return this.time(-0.01, true);
49653			  }
49654			});
49655			bodyStyle.borderTopStyle = "solid";
49656			bounds = _getBounds(_body$1);
49657			_vertical.m = Math.round(bounds.top + _vertical.sc()) || 0;
49658			_horizontal.m = Math.round(bounds.left + _horizontal.sc()) || 0;
49659			border ? bodyStyle.borderTopStyle = border : bodyStyle.removeProperty("border-top-style");
49660			_syncInterval = setInterval(_sync, 250);
49661			gsap$1.delayedCall(0.5, function () {
49662			  return _startup$1 = 0;
49663			});
49664  
49665			_addListener$1(_doc$1, "touchcancel", _passThrough);
49666  
49667			_addListener$1(_body$1, "touchstart", _passThrough);
49668  
49669			_multiListener(_addListener$1, _doc$1, "pointerdown,touchstart,mousedown", _pointerDownHandler);
49670  
49671			_multiListener(_addListener$1, _doc$1, "pointerup,touchend,mouseup", _pointerUpHandler);
49672  
49673			_transformProp = gsap$1.utils.checkPrefix("transform");
49674  
49675			_stateProps.push(_transformProp);
49676  
49677			_coreInitted$1 = _getTime$1();
49678			_resizeDelay = gsap$1.delayedCall(0.2, _refreshAll).pause();
49679			_autoRefresh = [_doc$1, "visibilitychange", function () {
49680			  var w = _win$1.innerWidth,
49681				  h = _win$1.innerHeight;
49682  
49683			  if (_doc$1.hidden) {
49684				_prevWidth = w;
49685				_prevHeight = h;
49686			  } else if (_prevWidth !== w || _prevHeight !== h) {
49687				_onResize();
49688			  }
49689			}, _doc$1, "DOMContentLoaded", _refreshAll, _win$1, "load", _refreshAll, _win$1, "resize", _onResize];
49690  
49691			_iterateAutoRefresh(_addListener$1);
49692  
49693			_triggers.forEach(function (trigger) {
49694			  return trigger.enable(0, 1);
49695			});
49696  
49697			for (i = 0; i < _scrollers.length; i += 3) {
49698			  _wheelListener(_removeListener$1, _scrollers[i], _scrollers[i + 1]);
49699  
49700			  _wheelListener(_removeListener$1, _scrollers[i], _scrollers[i + 2]);
49701			}
49702		  }
49703		}
49704	  };
49705  
49706	  ScrollTrigger.config = function config(vars) {
49707		"limitCallbacks" in vars && (_limitCallbacks = !!vars.limitCallbacks);
49708		var ms = vars.syncInterval;
49709		ms && clearInterval(_syncInterval) || (_syncInterval = ms) && setInterval(_sync, ms);
49710		"ignoreMobileResize" in vars && (_ignoreMobileResize = ScrollTrigger.isTouch === 1 && vars.ignoreMobileResize);
49711  
49712		if ("autoRefreshEvents" in vars) {
49713		  _iterateAutoRefresh(_removeListener$1) || _iterateAutoRefresh(_addListener$1, vars.autoRefreshEvents || "none");
49714		  _ignoreResize = (vars.autoRefreshEvents + "").indexOf("resize") === -1;
49715		}
49716	  };
49717  
49718	  ScrollTrigger.scrollerProxy = function scrollerProxy(target, vars) {
49719		var t = _getTarget(target),
49720			i = _scrollers.indexOf(t),
49721			isViewport = _isViewport$1(t);
49722  
49723		if (~i) {
49724		  _scrollers.splice(i, isViewport ? 6 : 2);
49725		}
49726  
49727		if (vars) {
49728		  isViewport ? _proxies.unshift(_win$1, vars, _body$1, vars, _docEl$1, vars) : _proxies.unshift(t, vars);
49729		}
49730	  };
49731  
49732	  ScrollTrigger.clearMatchMedia = function clearMatchMedia(query) {
49733		_triggers.forEach(function (t) {
49734		  return t._ctx && t._ctx.query === query && t._ctx.kill(true, true);
49735		});
49736	  };
49737  
49738	  ScrollTrigger.isInViewport = function isInViewport(element, ratio, horizontal) {
49739		var bounds = (_isString(element) ? _getTarget(element) : element).getBoundingClientRect(),
49740			offset = bounds[horizontal ? _width : _height] * ratio || 0;
49741		return horizontal ? bounds.right - offset > 0 && bounds.left + offset < _win$1.innerWidth : bounds.bottom - offset > 0 && bounds.top + offset < _win$1.innerHeight;
49742	  };
49743  
49744	  ScrollTrigger.positionInViewport = function positionInViewport(element, referencePoint, horizontal) {
49745		_isString(element) && (element = _getTarget(element));
49746		var bounds = element.getBoundingClientRect(),
49747			size = bounds[horizontal ? _width : _height],
49748			offset = referencePoint == null ? size / 2 : referencePoint in _keywords ? _keywords[referencePoint] * size : ~referencePoint.indexOf("%") ? parseFloat(referencePoint) * size / 100 : parseFloat(referencePoint) || 0;
49749		return horizontal ? (bounds.left + offset) / _win$1.innerWidth : (bounds.top + offset) / _win$1.innerHeight;
49750	  };
49751  
49752	  ScrollTrigger.killAll = function killAll(allowListeners) {
49753		_triggers.slice(0).forEach(function (t) {
49754		  return t.vars.id !== "ScrollSmoother" && t.kill();
49755		});
49756  
49757		if (allowListeners !== true) {
49758		  var listeners = _listeners.killAll || [];
49759		  _listeners = {};
49760		  listeners.forEach(function (f) {
49761			return f();
49762		  });
49763		}
49764	  };
49765  
49766	  return ScrollTrigger;
49767	}();
49768	ScrollTrigger$1.version = "3.12.5";
49769  
49770	ScrollTrigger$1.saveStyles = function (targets) {
49771	  return targets ? _toArray(targets).forEach(function (target) {
49772		if (target && target.style) {
49773		  var i = _savedStyles.indexOf(target);
49774  
49775		  i >= 0 && _savedStyles.splice(i, 5);
49776  
49777		  _savedStyles.push(target, target.style.cssText, target.getBBox && target.getAttribute("transform"), gsap$1.core.getCache(target), _context$1());
49778		}
49779	  }) : _savedStyles;
49780	};
49781  
49782	ScrollTrigger$1.revert = function (soft, media) {
49783	  return _revertAll(!soft, media);
49784	};
49785  
49786	ScrollTrigger$1.create = function (vars, animation) {
49787	  return new ScrollTrigger$1(vars, animation);
49788	};
49789  
49790	ScrollTrigger$1.refresh = function (safe) {
49791	  return safe ? _onResize() : (_coreInitted$1 || ScrollTrigger$1.register()) && _refreshAll(true);
49792	};
49793  
49794	ScrollTrigger$1.update = function (force) {
49795	  return ++_scrollers.cache && _updateAll(force === true ? 2 : 0);
49796	};
49797  
49798	ScrollTrigger$1.clearScrollMemory = _clearScrollMemory;
49799  
49800	ScrollTrigger$1.maxScroll = function (element, horizontal) {
49801	  return _maxScroll(element, horizontal ? _horizontal : _vertical);
49802	};
49803  
49804	ScrollTrigger$1.getScrollFunc = function (element, horizontal) {
49805	  return _getScrollFunc(_getTarget(element), horizontal ? _horizontal : _vertical);
49806	};
49807  
49808	ScrollTrigger$1.getById = function (id) {
49809	  return _ids[id];
49810	};
49811  
49812	ScrollTrigger$1.getAll = function () {
49813	  return _triggers.filter(function (t) {
49814		return t.vars.id !== "ScrollSmoother";
49815	  });
49816	};
49817  
49818	ScrollTrigger$1.isScrolling = function () {
49819	  return !!_lastScrollTime;
49820	};
49821  
49822	ScrollTrigger$1.snapDirectional = _snapDirectional;
49823  
49824	ScrollTrigger$1.addEventListener = function (type, callback) {
49825	  var a = _listeners[type] || (_listeners[type] = []);
49826	  ~a.indexOf(callback) || a.push(callback);
49827	};
49828  
49829	ScrollTrigger$1.removeEventListener = function (type, callback) {
49830	  var a = _listeners[type],
49831		  i = a && a.indexOf(callback);
49832	  i >= 0 && a.splice(i, 1);
49833	};
49834  
49835	ScrollTrigger$1.batch = function (targets, vars) {
49836	  var result = [],
49837		  varsCopy = {},
49838		  interval = vars.interval || 0.016,
49839		  batchMax = vars.batchMax || 1e9,
49840		  proxyCallback = function proxyCallback(type, callback) {
49841		var elements = [],
49842			triggers = [],
49843			delay = gsap$1.delayedCall(interval, function () {
49844		  callback(elements, triggers);
49845		  elements = [];
49846		  triggers = [];
49847		}).pause();
49848		return function (self) {
49849		  elements.length || delay.restart(true);
49850		  elements.push(self.trigger);
49851		  triggers.push(self);
49852		  batchMax <= elements.length && delay.progress(1);
49853		};
49854	  },
49855		  p;
49856  
49857	  for (p in vars) {
49858		varsCopy[p] = p.substr(0, 2) === "on" && _isFunction(vars[p]) && p !== "onRefreshInit" ? proxyCallback(p, vars[p]) : vars[p];
49859	  }
49860  
49861	  if (_isFunction(batchMax)) {
49862		batchMax = batchMax();
49863  
49864		_addListener$1(ScrollTrigger$1, "refresh", function () {
49865		  return batchMax = vars.batchMax();
49866		});
49867	  }
49868  
49869	  _toArray(targets).forEach(function (target) {
49870		var config = {};
49871  
49872		for (p in varsCopy) {
49873		  config[p] = varsCopy[p];
49874		}
49875  
49876		config.trigger = target;
49877		result.push(ScrollTrigger$1.create(config));
49878	  });
49879  
49880	  return result;
49881	};
49882  
49883	var _clampScrollAndGetDurationMultiplier = function _clampScrollAndGetDurationMultiplier(scrollFunc, current, end, max) {
49884	  current > max ? scrollFunc(max) : current < 0 && scrollFunc(0);
49885	  return end > max ? (max - current) / (end - current) : end < 0 ? current / (current - end) : 1;
49886	},
49887		_allowNativePanning = function _allowNativePanning(target, direction) {
49888	  if (direction === true) {
49889		target.style.removeProperty("touch-action");
49890	  } else {
49891		target.style.touchAction = direction === true ? "auto" : direction ? "pan-" + direction + (Observer.isTouch ? " pinch-zoom" : "") : "none";
49892	  }
49893  
49894	  target === _docEl$1 && _allowNativePanning(_body$1, direction);
49895	},
49896		_overflow = {
49897	  auto: 1,
49898	  scroll: 1
49899	},
49900		_nestedScroll = function _nestedScroll(_ref5) {
49901	  var event = _ref5.event,
49902		  target = _ref5.target,
49903		  axis = _ref5.axis;
49904  
49905	  var node = (event.changedTouches ? event.changedTouches[0] : event).target,
49906		  cache = node._gsap || gsap$1.core.getCache(node),
49907		  time = _getTime$1(),
49908		  cs;
49909  
49910	  if (!cache._isScrollT || time - cache._isScrollT > 2000) {
49911		while (node && node !== _body$1 && (node.scrollHeight <= node.clientHeight && node.scrollWidth <= node.clientWidth || !(_overflow[(cs = _getComputedStyle(node)).overflowY] || _overflow[cs.overflowX]))) {
49912		  node = node.parentNode;
49913		}
49914  
49915		cache._isScroll = node && node !== target && !_isViewport$1(node) && (_overflow[(cs = _getComputedStyle(node)).overflowY] || _overflow[cs.overflowX]);
49916		cache._isScrollT = time;
49917	  }
49918  
49919	  if (cache._isScroll || axis === "x") {
49920		event.stopPropagation();
49921		event._gsapAllow = true;
49922	  }
49923	},
49924		_inputObserver = function _inputObserver(target, type, inputs, nested) {
49925	  return Observer.create({
49926		target: target,
49927		capture: true,
49928		debounce: false,
49929		lockAxis: true,
49930		type: type,
49931		onWheel: nested = nested && _nestedScroll,
49932		onPress: nested,
49933		onDrag: nested,
49934		onScroll: nested,
49935		onEnable: function onEnable() {
49936		  return inputs && _addListener$1(_doc$1, Observer.eventTypes[0], _captureInputs, false, true);
49937		},
49938		onDisable: function onDisable() {
49939		  return _removeListener$1(_doc$1, Observer.eventTypes[0], _captureInputs, true);
49940		}
49941	  });
49942	},
49943		_inputExp = /(input|label|select|textarea)/i,
49944		_inputIsFocused,
49945		_captureInputs = function _captureInputs(e) {
49946	  var isInput = _inputExp.test(e.target.tagName);
49947  
49948	  if (isInput || _inputIsFocused) {
49949		e._gsapAllow = true;
49950		_inputIsFocused = isInput;
49951	  }
49952	},
49953		_getScrollNormalizer = function _getScrollNormalizer(vars) {
49954	  _isObject(vars) || (vars = {});
49955	  vars.preventDefault = vars.isNormalizer = vars.allowClicks = true;
49956	  vars.type || (vars.type = "wheel,touch");
49957	  vars.debounce = !!vars.debounce;
49958	  vars.id = vars.id || "normalizer";
49959  
49960	  var _vars2 = vars,
49961		  normalizeScrollX = _vars2.normalizeScrollX,
49962		  momentum = _vars2.momentum,
49963		  allowNestedScroll = _vars2.allowNestedScroll,
49964		  onRelease = _vars2.onRelease,
49965		  self,
49966		  maxY,
49967		  target = _getTarget(vars.target) || _docEl$1,
49968		  smoother = gsap$1.core.globals().ScrollSmoother,
49969		  smootherInstance = smoother && smoother.get(),
49970		  content = _fixIOSBug && (vars.content && _getTarget(vars.content) || smootherInstance && vars.content !== false && !smootherInstance.smooth() && smootherInstance.content()),
49971		  scrollFuncY = _getScrollFunc(target, _vertical),
49972		  scrollFuncX = _getScrollFunc(target, _horizontal),
49973		  scale = 1,
vendor: 4,132 bytes, lines 49974-50095
49974		  initialScale = (Observer.isTouch && _win$1.visualViewport ? _win$1.visualViewport.scale * _win$1.visualViewport.width : _win$1.outerWidth) / _win$1.innerWidth,
49975		  wheelRefresh = 0,
49976		  resolveMomentumDuration = _isFunction(momentum) ? function () {
49977		return momentum(self);
49978	  } : function () {
49979		return momentum || 2.8;
49980	  },
49981		  lastRefreshID,
49982		  skipTouchMove,
49983		  inputObserver = _inputObserver(target, vars.type, true, allowNestedScroll),
49984		  resumeTouchMove = function resumeTouchMove() {
49985		return skipTouchMove = false;
49986	  },
49987		  scrollClampX = _passThrough,
49988		  scrollClampY = _passThrough,
49989		  updateClamps = function updateClamps() {
49990		maxY = _maxScroll(target, _vertical);
49991		scrollClampY = _clamp$1(_fixIOSBug ? 1 : 0, maxY);
49992		normalizeScrollX && (scrollClampX = _clamp$1(0, _maxScroll(target, _horizontal)));
49993		lastRefreshID = _refreshID;
49994	  },
49995		  removeContentOffset = function removeContentOffset() {
49996		content._gsap.y = _round(parseFloat(content._gsap.y) + scrollFuncY.offset) + "px";
49997		content.style.transform = "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, " + parseFloat(content._gsap.y) + ", 0, 1)";
49998		scrollFuncY.offset = scrollFuncY.cacheID = 0;
49999	  },
50000		  ignoreDrag = function ignoreDrag() {
50001		if (skipTouchMove) {
50002		  requestAnimationFrame(resumeTouchMove);
50003  
50004		  var offset = _round(self.deltaY / 2),
50005			  scroll = scrollClampY(scrollFuncY.v - offset);
50006  
50007		  if (content && scroll !== scrollFuncY.v + scrollFuncY.offset) {
50008			scrollFuncY.offset = scroll - scrollFuncY.v;
50009  
50010			var y = _round((parseFloat(content && content._gsap.y) || 0) - scrollFuncY.offset);
50011  
50012			content.style.transform = "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, " + y + ", 0, 1)";
50013			content._gsap.y = y + "px";
50014			scrollFuncY.cacheID = _scrollers.cache;
50015  
50016			_updateAll();
50017		  }
50018  
50019		  return true;
50020		}
50021  
50022		scrollFuncY.offset && removeContentOffset();
50023		skipTouchMove = true;
50024	  },
50025		  tween,
50026		  startScrollX,
50027		  startScrollY,
50028		  onStopDelayedCall,
50029		  onResize = function onResize() {
50030		updateClamps();
50031  
50032		if (tween.isActive() && tween.vars.scrollY > maxY) {
50033		  scrollFuncY() > maxY ? tween.progress(1) && scrollFuncY(maxY) : tween.resetTo("scrollY", maxY);
50034		}
50035	  };
50036  
50037	  content && gsap$1.set(content, {
50038		y: "+=0"
50039	  });
50040  
50041	  vars.ignoreCheck = function (e) {
50042		return _fixIOSBug && e.type === "touchmove" && ignoreDrag() || scale > 1.05 && e.type !== "touchstart" || self.isGesturing || e.touches && e.touches.length > 1;
50043	  };
50044  
50045	  vars.onPress = function () {
50046		skipTouchMove = false;
50047		var prevScale = scale;
50048		scale = _round((_win$1.visualViewport && _win$1.visualViewport.scale || 1) / initialScale);
50049		tween.pause();
50050		prevScale !== scale && _allowNativePanning(target, scale > 1.01 ? true : normalizeScrollX ? false : "x");
50051		startScrollX = scrollFuncX();
50052		startScrollY = scrollFuncY();
50053		updateClamps();
50054		lastRefreshID = _refreshID;
50055	  };
50056  
50057	  vars.onRelease = vars.onGestureStart = function (self, wasDragging) {
50058		scrollFuncY.offset && removeContentOffset();
50059  
50060		if (!wasDragging) {
50061		  onStopDelayedCall.restart(true);
50062		} else {
50063		  _scrollers.cache++;
50064		  var dur = resolveMomentumDuration(),
50065			  currentScroll,
50066			  endScroll;
50067  
50068		  if (normalizeScrollX) {
50069			currentScroll = scrollFuncX();
50070			endScroll = currentScroll + dur * 0.05 * -self.velocityX / 0.227;
50071			dur *= _clampScrollAndGetDurationMultiplier(scrollFuncX, currentScroll, endScroll, _maxScroll(target, _horizontal));
50072			tween.vars.scrollX = scrollClampX(endScroll);
50073		  }
50074  
50075		  currentScroll = scrollFuncY();
50076		  endScroll = currentScroll + dur * 0.05 * -self.velocityY / 0.227;
50077		  dur *= _clampScrollAndGetDurationMultiplier(scrollFuncY, currentScroll, endScroll, _maxScroll(target, _vertical));
50078		  tween.vars.scrollY = scrollClampY(endScroll);
50079		  tween.invalidate().duration(dur).play(0.01);
50080  
50081		  if (_fixIOSBug && tween.vars.scrollY >= maxY || currentScroll >= maxY - 1) {
50082			gsap$1.to({}, {
50083			  onUpdate: onResize,
50084			  duration: dur
50085			});
50086		  }
50087		}
50088  
50089		onRelease && onRelease(self);
50090	  };
50091  
50092	  vars.onWheel = function () {
50093		tween._ts && tween.pause();
50094  
50095		if (_getTime$1() - wheelRefresh > 1000) {
vendor: 28,617 bytes, lines 50096-51150
50096		  lastRefreshID = 0;
50097		  wheelRefresh = _getTime$1();
50098		}
50099	  };
50100  
50101	  vars.onChange = function (self, dx, dy, xArray, yArray) {
50102		_refreshID !== lastRefreshID && updateClamps();
50103		dx && normalizeScrollX && scrollFuncX(scrollClampX(xArray[2] === dx ? startScrollX + (self.startX - self.x) : scrollFuncX() + dx - xArray[1]));
50104  
50105		if (dy) {
50106		  scrollFuncY.offset && removeContentOffset();
50107		  var isTouch = yArray[2] === dy,
50108			  y = isTouch ? startScrollY + self.startY - self.y : scrollFuncY() + dy - yArray[1],
50109			  yClamped = scrollClampY(y);
50110		  isTouch && y !== yClamped && (startScrollY += yClamped - y);
50111		  scrollFuncY(yClamped);
50112		}
50113  
50114		(dy || dx) && _updateAll();
50115	  };
50116  
50117	  vars.onEnable = function () {
50118		_allowNativePanning(target, normalizeScrollX ? false : "x");
50119  
50120		ScrollTrigger$1.addEventListener("refresh", onResize);
50121  
50122		_addListener$1(_win$1, "resize", onResize);
50123  
50124		if (scrollFuncY.smooth) {
50125		  scrollFuncY.target.style.scrollBehavior = "auto";
50126		  scrollFuncY.smooth = scrollFuncX.smooth = false;
50127		}
50128  
50129		inputObserver.enable();
50130	  };
50131  
50132	  vars.onDisable = function () {
50133		_allowNativePanning(target, true);
50134  
50135		_removeListener$1(_win$1, "resize", onResize);
50136  
50137		ScrollTrigger$1.removeEventListener("refresh", onResize);
50138		inputObserver.kill();
50139	  };
50140  
50141	  vars.lockAxis = vars.lockAxis !== false;
50142	  self = new Observer(vars);
50143	  self.iOS = _fixIOSBug;
50144	  _fixIOSBug && !scrollFuncY() && scrollFuncY(1);
50145	  _fixIOSBug && gsap$1.ticker.add(_passThrough);
50146	  onStopDelayedCall = self._dc;
50147	  tween = gsap$1.to(self, {
50148		ease: "power4",
50149		paused: true,
50150		inherit: false,
50151		scrollX: normalizeScrollX ? "+=0.1" : "+=0",
50152		scrollY: "+=0.1",
50153		modifiers: {
50154		  scrollY: _interruptionTracker(scrollFuncY, scrollFuncY(), function () {
50155			return tween.pause();
50156		  })
50157		},
50158		onUpdate: _updateAll,
50159		onComplete: onStopDelayedCall.vars.onComplete
50160	  });
50161	  return self;
50162	};
50163  
50164	ScrollTrigger$1.sort = function (func) {
50165	  return _triggers.sort(func || function (a, b) {
50166		return (a.vars.refreshPriority || 0) * -1e6 + a.start - (b.start + (b.vars.refreshPriority || 0) * -1e6);
50167	  });
50168	};
50169  
50170	ScrollTrigger$1.observe = function (vars) {
50171	  return new Observer(vars);
50172	};
50173  
50174	ScrollTrigger$1.normalizeScroll = function (vars) {
50175	  if (typeof vars === "undefined") {
50176		return _normalizer$1;
50177	  }
50178  
50179	  if (vars === true && _normalizer$1) {
50180		return _normalizer$1.enable();
50181	  }
50182  
50183	  if (vars === false) {
50184		_normalizer$1 && _normalizer$1.kill();
50185		_normalizer$1 = vars;
50186		return;
50187	  }
50188  
50189	  var normalizer = vars instanceof Observer ? vars : _getScrollNormalizer(vars);
50190	  _normalizer$1 && _normalizer$1.target === normalizer.target && _normalizer$1.kill();
50191	  _isViewport$1(normalizer.target) && (_normalizer$1 = normalizer);
50192	  return normalizer;
50193	};
50194  
50195	ScrollTrigger$1.core = {
50196	  _getVelocityProp: _getVelocityProp,
50197	  _inputObserver: _inputObserver,
50198	  _scrollers: _scrollers,
50199	  _proxies: _proxies,
50200	  bridge: {
50201		ss: function ss() {
50202		  _lastScrollTime || _dispatch("scrollStart");
50203		  _lastScrollTime = _getTime$1();
50204		},
50205		ref: function ref() {
50206		  return _refreshing;
50207		}
50208	  }
50209	};
50210	_getGSAP$1() && gsap$1.registerPlugin(ScrollTrigger$1);
50211  
50212	exports.ScrollTrigger = ScrollTrigger$1;
50213	exports.default = ScrollTrigger$1;
50214  
50215	if (typeof(window) === 'undefined' || window !== exports) {Object.defineProperty(exports, '__esModule', { value: true });} else {delete window.default;}
50216  
50217  })));
50218
50219/*!
50220 * CustomEase 3.12.7
50221 * https://gsap.com
50222 * 
50223 * @license Copyright 2025, GreenSock. All rights reserved.
50224 * Subject to the terms at https://gsap.com/standard-license or for Club GSAP members, the agreement issued with that membership.
50225 * @author: Jack Doyle, [email protected]
50226 */
50227
50228  (function (global, factory) {
50229	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
50230	typeof define === 'function' && define.amd ? define(['exports'], factory) :
50231	(global = global || self, factory(global.window = global.window || {}));
50232}(this, (function (exports) { 'use strict';
50233
50234	var _svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
50235	    _scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig,
50236	    _DEG2RAD = Math.PI / 180,
50237	    _sin = Math.sin,
50238	    _cos = Math.cos,
50239	    _abs = Math.abs,
50240	    _sqrt = Math.sqrt,
50241	    _isNumber = function _isNumber(value) {
50242	  return typeof value === "number";
50243	},
50244	    _roundingNum = 1e5,
50245	    _round = function _round(value) {
50246	  return Math.round(value * _roundingNum) / _roundingNum || 0;
50247	};
50248	function transformRawPath(rawPath, a, b, c, d, tx, ty) {
50249	  var j = rawPath.length,
50250	      segment,
50251	      l,
50252	      i,
50253	      x,
50254	      y;
50255
50256	  while (--j > -1) {
50257	    segment = rawPath[j];
50258	    l = segment.length;
50259
50260	    for (i = 0; i < l; i += 2) {
50261	      x = segment[i];
50262	      y = segment[i + 1];
50263	      segment[i] = x * a + y * c + tx;
50264	      segment[i + 1] = x * b + y * d + ty;
50265	    }
50266	  }
50267
50268	  rawPath._dirty = 1;
50269	  return rawPath;
50270	}
50271
50272	function arcToSegment(lastX, lastY, rx, ry, angle, largeArcFlag, sweepFlag, x, y) {
50273	  if (lastX === x && lastY === y) {
50274	    return;
50275	  }
50276
50277	  rx = _abs(rx);
50278	  ry = _abs(ry);
50279
50280	  var angleRad = angle % 360 * _DEG2RAD,
50281	      cosAngle = _cos(angleRad),
50282	      sinAngle = _sin(angleRad),
50283	      PI = Math.PI,
50284	      TWOPI = PI * 2,
50285	      dx2 = (lastX - x) / 2,
50286	      dy2 = (lastY - y) / 2,
50287	      x1 = cosAngle * dx2 + sinAngle * dy2,
50288	      y1 = -sinAngle * dx2 + cosAngle * dy2,
50289	      x1_sq = x1 * x1,
50290	      y1_sq = y1 * y1,
50291	      radiiCheck = x1_sq / (rx * rx) + y1_sq / (ry * ry);
50292
50293	  if (radiiCheck > 1) {
50294	    rx = _sqrt(radiiCheck) * rx;
50295	    ry = _sqrt(radiiCheck) * ry;
50296	  }
50297
50298	  var rx_sq = rx * rx,
50299	      ry_sq = ry * ry,
50300	      sq = (rx_sq * ry_sq - rx_sq * y1_sq - ry_sq * x1_sq) / (rx_sq * y1_sq + ry_sq * x1_sq);
50301
50302	  if (sq < 0) {
50303	    sq = 0;
50304	  }
50305
50306	  var coef = (largeArcFlag === sweepFlag ? -1 : 1) * _sqrt(sq),
50307	      cx1 = coef * (rx * y1 / ry),
50308	      cy1 = coef * -(ry * x1 / rx),
50309	      sx2 = (lastX + x) / 2,
50310	      sy2 = (lastY + y) / 2,
50311	      cx = sx2 + (cosAngle * cx1 - sinAngle * cy1),
50312	      cy = sy2 + (sinAngle * cx1 + cosAngle * cy1),
50313	      ux = (x1 - cx1) / rx,
50314	      uy = (y1 - cy1) / ry,
50315	      vx = (-x1 - cx1) / rx,
50316	      vy = (-y1 - cy1) / ry,
50317	      temp = ux * ux + uy * uy,
50318	      angleStart = (uy < 0 ? -1 : 1) * Math.acos(ux / _sqrt(temp)),
50319	      angleExtent = (ux * vy - uy * vx < 0 ? -1 : 1) * Math.acos((ux * vx + uy * vy) / _sqrt(temp * (vx * vx + vy * vy)));
50320
50321	  isNaN(angleExtent) && (angleExtent = PI);
50322
50323	  if (!sweepFlag && angleExtent > 0) {
50324	    angleExtent -= TWOPI;
50325	  } else if (sweepFlag && angleExtent < 0) {
50326	    angleExtent += TWOPI;
50327	  }
50328
50329	  angleStart %= TWOPI;
50330	  angleExtent %= TWOPI;
50331
50332	  var segments = Math.ceil(_abs(angleExtent) / (TWOPI / 4)),
50333	      rawPath = [],
50334	      angleIncrement = angleExtent / segments,
50335	      controlLength = 4 / 3 * _sin(angleIncrement / 2) / (1 + _cos(angleIncrement / 2)),
50336	      ma = cosAngle * rx,
50337	      mb = sinAngle * rx,
50338	      mc = sinAngle * -ry,
50339	      md = cosAngle * ry,
50340	      i;
50341
50342	  for (i = 0; i < segments; i++) {
50343	    angle = angleStart + i * angleIncrement;
50344	    x1 = _cos(angle);
50345	    y1 = _sin(angle);
50346	    ux = _cos(angle += angleIncrement);
50347	    uy = _sin(angle);
50348	    rawPath.push(x1 - controlLength * y1, y1 + controlLength * x1, ux + controlLength * uy, uy - controlLength * ux, ux, uy);
50349	  }
50350
50351	  for (i = 0; i < rawPath.length; i += 2) {
50352	    x1 = rawPath[i];
50353	    y1 = rawPath[i + 1];
50354	    rawPath[i] = x1 * ma + y1 * mc + cx;
50355	    rawPath[i + 1] = x1 * mb + y1 * md + cy;
50356	  }
50357
50358	  rawPath[i - 2] = x;
50359	  rawPath[i - 1] = y;
50360	  return rawPath;
50361	}
50362
50363	function stringToRawPath(d) {
50364	  var a = (d + "").replace(_scientific, function (m) {
50365	    var n = +m;
50366	    return n < 0.0001 && n > -0.0001 ? 0 : n;
50367	  }).match(_svgPathExp) || [],
50368	      path = [],
50369	      relativeX = 0,
50370	      relativeY = 0,
50371	      twoThirds = 2 / 3,
50372	      elements = a.length,
50373	      points = 0,
50374	      errorMessage = "ERROR: malformed path: " + d,
50375	      i,
50376	      j,
50377	      x,
50378	      y,
50379	      command,
50380	      isRelative,
50381	      segment,
50382	      startX,
50383	      startY,
50384	      difX,
50385	      difY,
50386	      beziers,
50387	      prevCommand,
50388	      flag1,
50389	      flag2,
50390	      line = function line(sx, sy, ex, ey) {
50391	    difX = (ex - sx) / 3;
50392	    difY = (ey - sy) / 3;
50393	    segment.push(sx + difX, sy + difY, ex - difX, ey - difY, ex, ey);
50394	  };
50395
50396	  if (!d || !isNaN(a[0]) || isNaN(a[1])) {
50397	    console.log(errorMessage);
50398	    return path;
50399	  }
50400
50401	  for (i = 0; i < elements; i++) {
50402	    prevCommand = command;
50403
50404	    if (isNaN(a[i])) {
50405	      command = a[i].toUpperCase();
50406	      isRelative = command !== a[i];
50407	    } else {
50408	      i--;
50409	    }
50410
50411	    x = +a[i + 1];
50412	    y = +a[i + 2];
50413
50414	    if (isRelative) {
50415	      x += relativeX;
50416	      y += relativeY;
50417	    }
50418
50419	    if (!i) {
50420	      startX = x;
50421	      startY = y;
50422	    }
50423
50424	    if (command === "M") {
50425	      if (segment) {
50426	        if (segment.length < 8) {
50427	          path.length -= 1;
50428	        } else {
50429	          points += segment.length;
50430	        }
50431	      }
50432
50433	      relativeX = startX = x;
50434	      relativeY = startY = y;
50435	      segment = [x, y];
50436	      path.push(segment);
50437	      i += 2;
50438	      command = "L";
50439	    } else if (command === "C") {
50440	      if (!segment) {
50441	        segment = [0, 0];
50442	      }
50443
50444	      if (!isRelative) {
50445	        relativeX = relativeY = 0;
50446	      }
50447
50448	      segment.push(x, y, relativeX + a[i + 3] * 1, relativeY + a[i + 4] * 1, relativeX += a[i + 5] * 1, relativeY += a[i + 6] * 1);
50449	      i += 6;
50450	    } else if (command === "S") {
50451	      difX = relativeX;
50452	      difY = relativeY;
50453
50454	      if (prevCommand === "C" || prevCommand === "S") {
50455	        difX += relativeX - segment[segment.length - 4];
50456	        difY += relativeY - segment[segment.length - 3];
50457	      }
50458
50459	      if (!isRelative) {
50460	        relativeX = relativeY = 0;
50461	      }
50462
50463	      segment.push(difX, difY, x, y, relativeX += a[i + 3] * 1, relativeY += a[i + 4] * 1);
50464	      i += 4;
50465	    } else if (command === "Q") {
50466	      difX = relativeX + (x - relativeX) * twoThirds;
50467	      difY = relativeY + (y - relativeY) * twoThirds;
50468
50469	      if (!isRelative) {
50470	        relativeX = relativeY = 0;
50471	      }
50472
50473	      relativeX += a[i + 3] * 1;
50474	      relativeY += a[i + 4] * 1;
50475	      segment.push(difX, difY, relativeX + (x - relativeX) * twoThirds, relativeY + (y - relativeY) * twoThirds, relativeX, relativeY);
50476	      i += 4;
50477	    } else if (command === "T") {
50478	      difX = relativeX - segment[segment.length - 4];
50479	      difY = relativeY - segment[segment.length - 3];
50480	      segment.push(relativeX + difX, relativeY + difY, x + (relativeX + difX * 1.5 - x) * twoThirds, y + (relativeY + difY * 1.5 - y) * twoThirds, relativeX = x, relativeY = y);
50481	      i += 2;
50482	    } else if (command === "H") {
50483	      line(relativeX, relativeY, relativeX = x, relativeY);
50484	      i += 1;
50485	    } else if (command === "V") {
50486	      line(relativeX, relativeY, relativeX, relativeY = x + (isRelative ? relativeY - relativeX : 0));
50487	      i += 1;
50488	    } else if (command === "L" || command === "Z") {
50489	      if (command === "Z") {
50490	        x = startX;
50491	        y = startY;
50492	        segment.closed = true;
50493	      }
50494
50495	      if (command === "L" || _abs(relativeX - x) > 0.5 || _abs(relativeY - y) > 0.5) {
50496	        line(relativeX, relativeY, x, y);
50497
50498	        if (command === "L") {
50499	          i += 2;
50500	        }
50501	      }
50502
50503	      relativeX = x;
50504	      relativeY = y;
50505	    } else if (command === "A") {
50506	      flag1 = a[i + 4];
50507	      flag2 = a[i + 5];
50508	      difX = a[i + 6];
50509	      difY = a[i + 7];
50510	      j = 7;
50511
50512	      if (flag1.length > 1) {
50513	        if (flag1.length < 3) {
50514	          difY = difX;
50515	          difX = flag2;
50516	          j--;
50517	        } else {
50518	          difY = flag2;
50519	          difX = flag1.substr(2);
50520	          j -= 2;
50521	        }
50522
50523	        flag2 = flag1.charAt(1);
50524	        flag1 = flag1.charAt(0);
50525	      }
50526
50527	      beziers = arcToSegment(relativeX, relativeY, +a[i + 1], +a[i + 2], +a[i + 3], +flag1, +flag2, (isRelative ? relativeX : 0) + difX * 1, (isRelative ? relativeY : 0) + difY * 1);
50528	      i += j;
50529
50530	      if (beziers) {
50531	        for (j = 0; j < beziers.length; j++) {
50532	          segment.push(beziers[j]);
50533	        }
50534	      }
50535
50536	      relativeX = segment[segment.length - 2];
50537	      relativeY = segment[segment.length - 1];
50538	    } else {
50539	      console.log(errorMessage);
50540	    }
50541	  }
50542
50543	  i = segment.length;
50544
50545	  if (i < 6) {
50546	    path.pop();
50547	    i = 0;
50548	  } else if (segment[0] === segment[i - 2] && segment[1] === segment[i - 1]) {
50549	    segment.closed = true;
50550	  }
50551
50552	  path.totalPoints = points + i;
50553	  return path;
50554	}
50555	function rawPathToString(rawPath) {
50556	  if (_isNumber(rawPath[0])) {
50557	    rawPath = [rawPath];
50558	  }
50559
50560	  var result = "",
50561	      l = rawPath.length,
50562	      sl,
50563	      s,
50564	      i,
50565	      segment;
50566
50567	  for (s = 0; s < l; s++) {
50568	    segment = rawPath[s];
50569	    result += "M" + _round(segment[0]) + "," + _round(segment[1]) + " C";
50570	    sl = segment.length;
50571
50572	    for (i = 2; i < sl; i++) {
50573	      result += _round(segment[i++]) + "," + _round(segment[i++]) + " " + _round(segment[i++]) + "," + _round(segment[i++]) + " " + _round(segment[i++]) + "," + _round(segment[i]) + " ";
50574	    }
50575
50576	    if (segment.closed) {
50577	      result += "z";
50578	    }
50579	  }
50580
50581	  return result;
50582	}
50583
50584	/*!
50585	 * CustomEase 3.12.7
50586	 * https://gsap.com
50587	 *
50588	 * @license Copyright 2008-2025, GreenSock. All rights reserved.
50589	 * Subject to the terms at https://gsap.com/standard-license or for
50590	 * Club GSAP members, the agreement issued with that membership.
50591	 * @author: Jack Doyle, [email protected]
50592	*/
50593
50594	var gsap,
50595	    _coreInitted,
50596	    _getGSAP = function _getGSAP() {
50597	  return gsap || typeof window !== "undefined" && (gsap = window.gsap) && gsap.registerPlugin && gsap;
50598	},
50599	    _initCore = function _initCore() {
50600	  gsap = _getGSAP();
50601
50602	  if (gsap) {
50603	    gsap.registerEase("_CE", CustomEase.create);
50604	    _coreInitted = 1;
50605	  } else {
50606	    console.warn("Please gsap.registerPlugin(CustomEase)");
50607	  }
50608	},
50609	    _bigNum = 1e20,
50610	    _round$1 = function _round(value) {
50611	  return ~~(value * 1000 + (value < 0 ? -.5 : .5)) / 1000;
50612	},
50613	    _numExp = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/gi,
50614	    _needsParsingExp = /[cLlsSaAhHvVtTqQ]/g,
50615	    _findMinimum = function _findMinimum(values) {
50616	  var l = values.length,
50617	      min = _bigNum,
50618	      i;
50619
50620	  for (i = 1; i < l; i += 6) {
50621	    +values[i] < min && (min = +values[i]);
50622	  }
50623
50624	  return min;
50625	},
50626	    _normalize = function _normalize(values, height, originY) {
50627	  if (!originY && originY !== 0) {
50628	    originY = Math.max(+values[values.length - 1], +values[1]);
50629	  }
50630
50631	  var tx = +values[0] * -1,
50632	      ty = -originY,
50633	      l = values.length,
50634	      sx = 1 / (+values[l - 2] + tx),
50635	      sy = -height || (Math.abs(+values[l - 1] - +values[1]) < 0.01 * (+values[l - 2] - +values[0]) ? _findMinimum(values) + ty : +values[l - 1] + ty),
50636	      i;
50637
50638	  if (sy) {
50639	    sy = 1 / sy;
50640	  } else {
50641	    sy = -sx;
50642	  }
50643
50644	  for (i = 0; i < l; i += 2) {
50645	    values[i] = (+values[i] + tx) * sx;
50646	    values[i + 1] = (+values[i + 1] + ty) * sy;
50647	  }
50648	},
50649	    _bezierToPoints = function _bezierToPoints(x1, y1, x2, y2, x3, y3, x4, y4, threshold, points, index) {
50650	  var x12 = (x1 + x2) / 2,
50651	      y12 = (y1 + y2) / 2,
50652	      x23 = (x2 + x3) / 2,
50653	      y23 = (y2 + y3) / 2,
50654	      x34 = (x3 + x4) / 2,
50655	      y34 = (y3 + y4) / 2,
50656	      x123 = (x12 + x23) / 2,
50657	      y123 = (y12 + y23) / 2,
50658	      x234 = (x23 + x34) / 2,
50659	      y234 = (y23 + y34) / 2,
50660	      x1234 = (x123 + x234) / 2,
50661	      y1234 = (y123 + y234) / 2,
50662	      dx = x4 - x1,
50663	      dy = y4 - y1,
50664	      d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx),
50665	      d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx),
50666	      length;
50667
50668	  if (!points) {
50669	    points = [{
50670	      x: x1,
50671	      y: y1
50672	    }, {
50673	      x: x4,
50674	      y: y4
50675	    }];
50676	    index = 1;
50677	  }
50678
50679	  points.splice(index || points.length - 1, 0, {
50680	    x: x1234,
50681	    y: y1234
50682	  });
50683
50684	  if ((d2 + d3) * (d2 + d3) > threshold * (dx * dx + dy * dy)) {
50685	    length = points.length;
50686
50687	    _bezierToPoints(x1, y1, x12, y12, x123, y123, x1234, y1234, threshold, points, index);
50688
50689	    _bezierToPoints(x1234, y1234, x234, y234, x34, y34, x4, y4, threshold, points, index + 1 + (points.length - length));
50690	  }
50691
50692	  return points;
50693	};
50694
50695	var CustomEase = function () {
50696	  function CustomEase(id, data, config) {
50697	    _coreInitted || _initCore();
50698	    this.id = id;
50699	     this.setData(data, config);
50700	  }
50701
50702	  var _proto = CustomEase.prototype;
50703
50704	  _proto.setData = function setData(data, config) {
50705	    config = config || {};
50706	    data = data || "0,0,1,1";
50707	    var values = data.match(_numExp),
50708	        closest = 1,
50709	        points = [],
50710	        lookup = [],
50711	        precision = config.precision || 1,
50712	        fast = precision <= 1,
50713	        l,
50714	        a1,
50715	        a2,
50716	        i,
50717	        inc,
50718	        j,
50719	        point,
50720	        prevPoint,
50721	        p;
50722	    this.data = data;
50723
50724	    if (_needsParsingExp.test(data) || ~data.indexOf("M") && data.indexOf("C") < 0) {
50725	      values = stringToRawPath(data)[0];
50726	    }
50727
50728	    l = values.length;
50729
50730	    if (l === 4) {
50731	      values.unshift(0, 0);
50732	      values.push(1, 1);
50733	      l = 8;
50734	    } else if ((l - 2) % 6) {
50735	      throw "Invalid CustomEase";
50736	    }
50737
50738	    if (+values[0] !== 0 || +values[l - 2] !== 1) {
50739	      _normalize(values, config.height, config.originY);
50740	    }
50741
50742	    this.segment = values;
50743
50744	    for (i = 2; i < l; i += 6) {
50745	      a1 = {
50746	        x: +values[i - 2],
50747	        y: +values[i - 1]
50748	      };
50749	      a2 = {
50750	        x: +values[i + 4],
50751	        y: +values[i + 5]
50752	      };
50753	      points.push(a1, a2);
50754
50755	      _bezierToPoints(a1.x, a1.y, +values[i], +values[i + 1], +values[i + 2], +values[i + 3], a2.x, a2.y, 1 / (precision * 200000), points, points.length - 1);
50756	    }
50757
50758	    l = points.length;
50759
50760	    for (i = 0; i < l; i++) {
50761	      point = points[i];
50762	      prevPoint = points[i - 1] || point;
50763
50764	      if ((point.x > prevPoint.x || prevPoint.y !== point.y && prevPoint.x === point.x || point === prevPoint) && point.x <= 1) {
50765	        prevPoint.cx = point.x - prevPoint.x;
50766	        prevPoint.cy = point.y - prevPoint.y;
50767	        prevPoint.n = point;
50768	        prevPoint.nx = point.x;
50769
50770	        if (fast && i > 1 && Math.abs(prevPoint.cy / prevPoint.cx - points[i - 2].cy / points[i - 2].cx) > 2) {
50771	          fast = 0;
50772	        }
50773
50774	        if (prevPoint.cx < closest) {
50775	          if (!prevPoint.cx) {
50776	            prevPoint.cx = 0.001;
50777
50778	            if (i === l - 1) {
50779	              prevPoint.x -= 0.001;
50780	              closest = Math.min(closest, 0.001);
50781	              fast = 0;
50782	            }
50783	          } else {
50784	            closest = prevPoint.cx;
50785	          }
50786	        }
50787	      } else {
50788	        points.splice(i--, 1);
50789	        l--;
50790	      }
50791	    }
50792
50793	    l = 1 / closest + 1 | 0;
50794	    inc = 1 / l;
50795	    j = 0;
50796	    point = points[0];
50797
50798	    if (fast) {
50799	      for (i = 0; i < l; i++) {
50800	        p = i * inc;
50801
50802	        if (point.nx < p) {
50803	          point = points[++j];
50804	        }
50805
50806	        a1 = point.y + (p - point.x) / point.cx * point.cy;
50807	        lookup[i] = {
50808	          x: p,
50809	          cx: inc,
50810	          y: a1,
50811	          cy: 0,
50812	          nx: 9
50813	        };
50814
50815	        if (i) {
50816	          lookup[i - 1].cy = a1 - lookup[i - 1].y;
50817	        }
50818	      }
50819
50820	      j = points[points.length - 1];
50821	      lookup[l - 1].cy = j.y - a1;
50822	      lookup[l - 1].cx = j.x - lookup[lookup.length - 1].x;
50823	    } else {
50824	      for (i = 0; i < l; i++) {
50825	        if (point.nx < i * inc) {
50826	          point = points[++j];
50827	        }
50828
50829	        lookup[i] = point;
50830	      }
50831
50832	      if (j < points.length - 1) {
50833	        lookup[i - 1] = points[points.length - 2];
50834	      }
50835	    }
50836
50837	    this.ease = function (p) {
50838	      var point = lookup[p * l | 0] || lookup[l - 1];
50839
50840	      if (point.nx < p) {
50841	        point = point.n;
50842	      }
50843
50844	      return point.y + (p - point.x) / point.cx * point.cy;
50845	    };
50846
50847	    this.ease.custom = this;
50848	    this.id && gsap && gsap.registerEase(this.id, this.ease);
50849	    return this;
50850	  };
50851
50852	  _proto.getSVGData = function getSVGData(config) {
50853	    return CustomEase.getSVGData(this, config);
50854	  };
50855
50856	  CustomEase.create = function create(id, data, config) {
50857	    return new CustomEase(id, data, config).ease;
50858	  };
50859
50860	  CustomEase.register = function register(core) {
50861	    gsap = core;
50862
50863	    _initCore();
50864	  };
50865
50866	  CustomEase.get = function get(id) {
50867	    return gsap.parseEase(id);
50868	  };
50869
50870	  CustomEase.getSVGData = function getSVGData(ease, config) {
50871	    config = config || {};
50872	    var width = config.width || 100,
50873	        height = config.height || 100,
50874	        x = config.x || 0,
50875	        y = (config.y || 0) + height,
50876	        e = gsap.utils.toArray(config.path)[0],
50877	        a,
50878	        slope,
50879	        i,
50880	        inc,
50881	        tx,
50882	        ty,
50883	        precision,
50884	        threshold,
50885	        prevX,
50886	        prevY;
50887
50888	    if (config.invert) {
50889	      height = -height;
50890	      y = 0;
50891	    }
50892
50893	    if (typeof ease === "string") {
50894	      ease = gsap.parseEase(ease);
50895	    }
50896
50897	    if (ease.custom) {
50898	      ease = ease.custom;
50899	    }
50900
50901	    if (ease instanceof CustomEase) {
50902	      a = rawPathToString(transformRawPath([ease.segment], width, 0, 0, -height, x, y));
50903	    } else {
50904	      a = [x, y];
50905	      precision = Math.max(5, (config.precision || 1) * 200);
50906	      inc = 1 / precision;
50907	      precision += 2;
50908	      threshold = 5 / precision;
50909	      prevX = _round$1(x + inc * width);
50910	      prevY = _round$1(y + ease(inc) * -height);
50911	      slope = (prevY - y) / (prevX - x);
50912
50913	      for (i = 2; i < precision; i++) {
50914	        tx = _round$1(x + i * inc * width);
50915	        ty = _round$1(y + ease(i * inc) * -height);
50916
50917	        if (Math.abs((ty - prevY) / (tx - prevX) - slope) > threshold || i === precision - 1) {
50918	          a.push(prevX, prevY);
50919	          slope = (ty - prevY) / (tx - prevX);
50920	        }
50921
50922	        prevX = tx;
50923	        prevY = ty;
50924	      }
50925
50926	      a = "M" + a.join(",");
50927	    }
50928
50929	    e && e.setAttribute("d", a);
50930	    return a;
50931	  };
50932
50933	  return CustomEase;
50934	}();
50935	CustomEase.version = "3.12.7";
50936	CustomEase.headless = true;
50937	_getGSAP() && gsap.registerPlugin(CustomEase);
50938
50939	exports.CustomEase = CustomEase;
50940	exports.default = CustomEase;
50941
50942	Object.defineProperty(exports, '__esModule', { value: true });
50943
50944})));
50945(function (global, factory) {
50946  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
50947  typeof define === 'function' && define.amd ? define(['exports'], factory) :
50948  (global = global || self, factory(global.window = global.window || {}));
50949}(this, (function (exports) { 'use strict';
50950
50951  function _inheritsLoose(subClass, superClass) {
50952    subClass.prototype = Object.create(superClass.prototype);
50953    subClass.prototype.constructor = subClass;
50954    subClass.__proto__ = superClass;
50955  }
50956
50957  function _assertThisInitialized(self) {
50958    if (self === void 0) {
50959      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
50960    }
50961
50962    return self;
50963  }
50964
50965  var _doc,
50966      _win,
50967      _docElement,
50968      _body,
50969      _divContainer,
50970      _svgContainer,
50971      _identityMatrix,
50972      _gEl,
50973      _transformProp = "transform",
50974      _transformOriginProp = _transformProp + "Origin",
50975      _hasOffsetBug,
50976      _setDoc = function _setDoc(element) {
50977    var doc = element.ownerDocument || element;
50978
50979    if (!(_transformProp in element.style) && "msTransform" in element.style) {
50980      _transformProp = "msTransform";
50981      _transformOriginProp = _transformProp + "Origin";
50982    }
50983
50984    while (doc.parentNode && (doc = doc.parentNode)) {}
50985
50986    _win = window;
50987    _identityMatrix = new Matrix2D();
50988
50989    if (doc) {
50990      _doc = doc;
50991      _docElement = doc.documentElement;
50992      _body = doc.body;
50993      _gEl = _doc.createElementNS("http://www.w3.org/2000/svg", "g");
50994      _gEl.style.transform = "none";
50995      var d1 = doc.createElement("div"),
50996          d2 = doc.createElement("div"),
50997          root = doc && (doc.body || doc.firstElementChild);
50998
50999      if (root && root.appendChild) {
51000        root.appendChild(d1);
51001        d1.appendChild(d2);
51002        d1.setAttribute("style", "position:static;transform:translate3d(0,0,1px)");
51003        _hasOffsetBug = d2.offsetParent !== d1;
51004        root.removeChild(d1);
51005      }
51006    }
51007
51008    return doc;
51009  },
51010      _forceNonZeroScale = function _forceNonZeroScale(e) {
51011    var a, cache;
51012
51013    while (e && e !== _body) {
51014      cache = e._gsap;
51015      cache && cache.uncache && cache.get(e, "x");
51016
51017      if (cache && !cache.scaleX && !cache.scaleY && cache.renderTransform) {
51018        cache.scaleX = cache.scaleY = 1e-4;
51019        cache.renderTransform(1, cache);
51020        a ? a.push(cache) : a = [cache];
51021      }
51022
51023      e = e.parentNode;
51024    }
51025
51026    return a;
51027  },
51028      _svgTemps = [],
51029      _divTemps = [],
51030      _getDocScrollTop = function _getDocScrollTop() {
51031    return _win.pageYOffset || _doc.scrollTop || _docElement.scrollTop || _body.scrollTop || 0;
51032  },
51033      _getDocScrollLeft = function _getDocScrollLeft() {
51034    return _win.pageXOffset || _doc.scrollLeft || _docElement.scrollLeft || _body.scrollLeft || 0;
51035  },
51036      _svgOwner = function _svgOwner(element) {
51037    return element.ownerSVGElement || ((element.tagName + "").toLowerCase() === "svg" ? element : null);
51038  },
51039      _isFixed = function _isFixed(element) {
51040    if (_win.getComputedStyle(element).position === "fixed") {
51041      return true;
51042    }
51043
51044    element = element.parentNode;
51045
51046    if (element && element.nodeType === 1) {
51047      return _isFixed(element);
51048    }
51049  },
51050      _createSibling = function _createSibling(element, i) {
51051    if (element.parentNode && (_doc || _setDoc(element))) {
51052      var svg = _svgOwner(element),
51053          ns = svg ? svg.getAttribute("xmlns") || "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml",
51054          type = svg ? i ? "rect" : "g" : "div",
51055          x = i !== 2 ? 0 : 100,
51056          y = i === 3 ? 100 : 0,
51057          css = "position:absolute;display:block;pointer-events:none;margin:0;padding:0;",
51058          e = _doc.createElementNS ? _doc.createElementNS(ns.replace(/^https/, "http"), type) : _doc.createElement(type);
51059
51060      if (i) {
51061        if (!svg) {
51062          if (!_divContainer) {
51063            _divContainer = _createSibling(element);
51064            _divContainer.style.cssText = css;
51065          }
51066
51067          e.style.cssText = css + "width:0.1px;height:0.1px;top:" + y + "px;left:" + x + "px";
51068
51069          _divContainer.appendChild(e);
51070        } else {
51071          _svgContainer || (_svgContainer = _createSibling(element));
51072          e.setAttribute("width", 0.01);
51073          e.setAttribute("height", 0.01);
51074          e.setAttribute("transform", "translate(" + x + "," + y + ")");
51075
51076          _svgContainer.appendChild(e);
51077        }
51078      }
51079
51080      return e;
51081    }
51082
51083    throw "Need document and parent.";
51084  },
51085      _consolidate = function _consolidate(m) {
51086    var c = new Matrix2D(),
51087        i = 0;
51088
51089    for (; i < m.numberOfItems; i++) {
51090      c.multiply(m.getItem(i).matrix);
51091    }
51092
51093    return c;
51094  },
51095      _getCTM = function _getCTM(svg) {
51096    var m = svg.getCTM(),
51097        transform;
51098
51099    if (!m) {
51100      transform = svg.style[_transformProp];
51101      svg.style[_transformProp] = "none";
51102      svg.appendChild(_gEl);
51103      m = _gEl.getCTM();
51104      svg.removeChild(_gEl);
51105      transform ? svg.style[_transformProp] = transform : svg.style.removeProperty(_transformProp.replace(/([A-Z])/g, "-$1").toLowerCase());
51106    }
51107
51108    return m || _identityMatrix.clone();
51109  },
51110      _placeSiblings = function _placeSiblings(element, adjustGOffset) {
51111    var svg = _svgOwner(element),
51112        isRootSVG = element === svg,
51113        siblings = svg ? _svgTemps : _divTemps,
51114        parent = element.parentNode,
51115        container,
51116        m,
51117        b,
51118        x,
51119        y,
51120        cs;
51121
51122    if (element === _win) {
51123      return element;
51124    }
51125
51126    siblings.length || siblings.push(_createSibling(element, 1), _createSibling(element, 2), _createSibling(element, 3));
51127    container = svg ? _svgContainer : _divContainer;
51128
51129    if (svg) {
51130      if (isRootSVG) {
51131        b = _getCTM(element);
51132        x = -b.e / b.a;
51133        y = -b.f / b.d;
51134        m = _identityMatrix;
51135      } else if (element.getBBox) {
51136        b = element.getBBox();
51137        m = element.transform ? element.transform.baseVal : {};
51138        m = !m.numberOfItems ? _identityMatrix : m.numberOfItems > 1 ? _consolidate(m) : m.getItem(0).matrix;
51139        x = m.a * b.x + m.c * b.y;
51140        y = m.b * b.x + m.d * b.y;
51141      } else {
51142        m = new Matrix2D();
51143        x = y = 0;
51144      }
51145
51146      if (adjustGOffset && element.tagName.toLowerCase() === "g") {
51147        x = y = 0;
51148      }
51149
51150      (isRootSVG ? svg : parent).appendChild(container);
vendor: 1,139 bytes, lines 51151-51186
51151      container.setAttribute("transform", "matrix(" + m.a + "," + m.b + "," + m.c + "," + m.d + "," + (m.e + x) + "," + (m.f + y) + ")");
51152    } else {
51153      x = y = 0;
51154
51155      if (_hasOffsetBug) {
51156        m = element.offsetParent;
51157        b = element;
51158
51159        while (b && (b = b.parentNode) && b !== m && b.parentNode) {
51160          if ((_win.getComputedStyle(b)[_transformProp] + "").length > 4) {
51161            x = b.offsetLeft;
51162            y = b.offsetTop;
51163            b = 0;
51164          }
51165        }
51166      }
51167
51168      cs = _win.getComputedStyle(element);
51169
51170      if (cs.position !== "absolute" && cs.position !== "fixed") {
51171        m = element.offsetParent;
51172
51173        while (parent && parent !== m) {
51174          x += parent.scrollLeft || 0;
51175          y += parent.scrollTop || 0;
51176          parent = parent.parentNode;
51177        }
51178      }
51179
51180      b = container.style;
51181      b.top = element.offsetTop - y + "px";
51182      b.left = element.offsetLeft - x + "px";
51183      b[_transformProp] = cs[_transformProp];
51184      b[_transformOriginProp] = cs[_transformOriginProp];
51185      b.position = cs.position === "fixed" ? "fixed" : "absolute";
51186      element.parentNode
vendor: 37,456 bytes, lines 51186-52441
51186.appendChild(container);
51187    }
51188
51189    return container;
51190  },
51191      _setMatrix = function _setMatrix(m, a, b, c, d, e, f) {
51192    m.a = a;
51193    m.b = b;
51194    m.c = c;
51195    m.d = d;
51196    m.e = e;
51197    m.f = f;
51198    return m;
51199  };
51200
51201  var Matrix2D = function () {
51202    function Matrix2D(a, b, c, d, e, f) {
51203      if (a === void 0) {
51204        a = 1;
51205      }
51206
51207      if (b === void 0) {
51208        b = 0;
51209      }
51210
51211      if (c === void 0) {
51212        c = 0;
51213      }
51214
51215      if (d === void 0) {
51216        d = 1;
51217      }
51218
51219      if (e === void 0) {
51220        e = 0;
51221      }
51222
51223      if (f === void 0) {
51224        f = 0;
51225      }
51226
51227      _setMatrix(this, a, b, c, d, e, f);
51228    }
51229
51230    var _proto = Matrix2D.prototype;
51231
51232    _proto.inverse = function inverse() {
51233      var a = this.a,
51234          b = this.b,
51235          c = this.c,
51236          d = this.d,
51237          e = this.e,
51238          f = this.f,
51239          determinant = a * d - b * c || 1e-10;
51240      return _setMatrix(this, d / determinant, -b / determinant, -c / determinant, a / determinant, (c * f - d * e) / determinant, -(a * f - b * e) / determinant);
51241    };
51242
51243    _proto.multiply = function multiply(matrix) {
51244      var a = this.a,
51245          b = this.b,
51246          c = this.c,
51247          d = this.d,
51248          e = this.e,
51249          f = this.f,
51250          a2 = matrix.a,
51251          b2 = matrix.c,
51252          c2 = matrix.b,
51253          d2 = matrix.d,
51254          e2 = matrix.e,
51255          f2 = matrix.f;
51256      return _setMatrix(this, a2 * a + c2 * c, a2 * b + c2 * d, b2 * a + d2 * c, b2 * b + d2 * d, e + e2 * a + f2 * c, f + e2 * b + f2 * d);
51257    };
51258
51259    _proto.clone = function clone() {
51260      return new Matrix2D(this.a, this.b, this.c, this.d, this.e, this.f);
51261    };
51262
51263    _proto.equals = function equals(matrix) {
51264      var a = this.a,
51265          b = this.b,
51266          c = this.c,
51267          d = this.d,
51268          e = this.e,
51269          f = this.f;
51270      return a === matrix.a && b === matrix.b && c === matrix.c && d === matrix.d && e === matrix.e && f === matrix.f;
51271    };
51272
51273    _proto.apply = function apply(point, decoratee) {
51274      if (decoratee === void 0) {
51275        decoratee = {};
51276      }
51277
51278      var x = point.x,
51279          y = point.y,
51280          a = this.a,
51281          b = this.b,
51282          c = this.c,
51283          d = this.d,
51284          e = this.e,
51285          f = this.f;
51286      decoratee.x = x * a + y * c + e || 0;
51287      decoratee.y = x * b + y * d + f || 0;
51288      return decoratee;
51289    };
51290
51291    return Matrix2D;
51292  }();
51293  function getGlobalMatrix(element, inverse, adjustGOffset, includeScrollInFixed) {
51294    if (!element || !element.parentNode || (_doc || _setDoc(element)).documentElement === element) {
51295      return new Matrix2D();
51296    }
51297
51298    var zeroScales = _forceNonZeroScale(element),
51299        svg = _svgOwner(element),
51300        temps = svg ? _svgTemps : _divTemps,
51301        container = _placeSiblings(element, adjustGOffset),
51302        b1 = temps[0].getBoundingClientRect(),
51303        b2 = temps[1].getBoundingClientRect(),
51304        b3 = temps[2].getBoundingClientRect(),
51305        parent = container.parentNode,
51306        isFixed = !includeScrollInFixed && _isFixed(element),
51307        m = new Matrix2D((b2.left - b1.left) / 100, (b2.top - b1.top) / 100, (b3.left - b1.left) / 100, (b3.top - b1.top) / 100, b1.left + (isFixed ? 0 : _getDocScrollLeft()), b1.top + (isFixed ? 0 : _getDocScrollTop()));
51308
51309    parent.removeChild(container);
51310
51311    if (zeroScales) {
51312      b1 = zeroScales.length;
51313
51314      while (b1--) {
51315        b2 = zeroScales[b1];
51316        b2.scaleX = b2.scaleY = 0;
51317        b2.renderTransform(1, b2);
51318      }
51319    }
51320
51321    return inverse ? m.inverse() : m;
51322  }
51323
51324  var gsap,
51325      _win$1,
51326      _doc$1,
51327      _docElement$1,
51328      _body$1,
51329      _tempDiv,
51330      _placeholderDiv,
51331      _coreInitted,
51332      _checkPrefix,
51333      _toArray,
51334      _supportsPassive,
51335      _isTouchDevice,
51336      _touchEventLookup,
51337      _isMultiTouching,
51338      _isAndroid,
51339      InertiaPlugin,
51340      _defaultCursor,
51341      _supportsPointer,
51342      _context,
51343      _getStyleSaver,
51344      _dragCount = 0,
51345      _windowExists = function _windowExists() {
51346    return typeof window !== "undefined";
51347  },
51348      _getGSAP = function _getGSAP() {
51349    return gsap || _windowExists() && (gsap = window.gsap) && gsap.registerPlugin && gsap;
51350  },
51351      _isFunction = function _isFunction(value) {
51352    return typeof value === "function";
51353  },
51354      _isObject = function _isObject(value) {
51355    return typeof value === "object";
51356  },
51357      _isUndefined = function _isUndefined(value) {
51358    return typeof value === "undefined";
51359  },
51360      _emptyFunc = function _emptyFunc() {
51361    return false;
51362  },
51363      _transformProp$1 = "transform",
51364      _transformOriginProp$1 = "transformOrigin",
51365      _round = function _round(value) {
51366    return Math.round(value * 10000) / 10000;
51367  },
51368      _isArray = Array.isArray,
51369      _createElement = function _createElement(type, ns) {
51370    var e = _doc$1.createElementNS ? _doc$1.createElementNS((ns || "http://www.w3.org/1999/xhtml").replace(/^https/, "http"), type) : _doc$1.createElement(type);
51371    return e.style ? e : _doc$1.createElement(type);
51372  },
51373      _RAD2DEG = 180 / Math.PI,
51374      _bigNum = 1e20,
51375      _identityMatrix$1 = new Matrix2D(),
51376      _getTime = Date.now || function () {
51377    return new Date().getTime();
51378  },
51379      _renderQueue = [],
51380      _lookup = {},
51381      _lookupCount = 0,
51382      _clickableTagExp = /^(?:a|input|textarea|button|select)$/i,
51383      _lastDragTime = 0,
51384      _temp1 = {},
51385      _windowProxy = {},
51386      _copy = function _copy(obj, factor) {
51387    var copy = {},
51388        p;
51389
51390    for (p in obj) {
51391      copy[p] = factor ? obj[p] * factor : obj[p];
51392    }
51393
51394    return copy;
51395  },
51396      _extend = function _extend(obj, defaults) {
51397    for (var p in defaults) {
51398      if (!(p in obj)) {
51399        obj[p] = defaults[p];
51400      }
51401    }
51402
51403    return obj;
51404  },
51405      _setTouchActionForAllDescendants = function _setTouchActionForAllDescendants(elements, value) {
51406    var i = elements.length,
51407        children;
51408
51409    while (i--) {
51410      value ? elements[i].style.touchAction = value : elements[i].style.removeProperty("touch-action");
51411      children = elements[i].children;
51412      children && children.length && _setTouchActionForAllDescendants(children, value);
51413    }
51414  },
51415      _renderQueueTick = function _renderQueueTick() {
51416    return _renderQueue.forEach(function (func) {
51417      return func();
51418    });
51419  },
51420      _addToRenderQueue = function _addToRenderQueue(func) {
51421    _renderQueue.push(func);
51422
51423    if (_renderQueue.length === 1) {
51424      gsap.ticker.add(_renderQueueTick);
51425    }
51426  },
51427      _renderQueueTimeout = function _renderQueueTimeout() {
51428    return !_renderQueue.length && gsap.ticker.remove(_renderQueueTick);
51429  },
51430      _removeFromRenderQueue = function _removeFromRenderQueue(func) {
51431    var i = _renderQueue.length;
51432
51433    while (i--) {
51434      if (_renderQueue[i] === func) {
51435        _renderQueue.splice(i, 1);
51436      }
51437    }
51438
51439    gsap.to(_renderQueueTimeout, {
51440      overwrite: true,
51441      delay: 15,
51442      duration: 0,
51443      onComplete: _renderQueueTimeout,
51444      data: "_draggable"
51445    });
51446  },
51447      _setDefaults = function _setDefaults(obj, defaults) {
51448    for (var p in defaults) {
51449      if (!(p in obj)) {
51450        obj[p] = defaults[p];
51451      }
51452    }
51453
51454    return obj;
51455  },
51456      _addListener = function _addListener(element, type, func, capture) {
51457    if (element.addEventListener) {
51458      var touchType = _touchEventLookup[type];
51459      capture = capture || (_supportsPassive ? {
51460        passive: false
51461      } : null);
51462      element.addEventListener(touchType || type, func, capture);
51463      touchType && type !== touchType && element.addEventListener(type, func, capture);
51464    }
51465  },
51466      _removeListener = function _removeListener(element, type, func, capture) {
51467    if (element.removeEventListener) {
51468      var touchType = _touchEventLookup[type];
51469      element.removeEventListener(touchType || type, func, capture);
51470      touchType && type !== touchType && element.removeEventListener(type, func, capture);
51471    }
51472  },
51473      _preventDefault = function _preventDefault(event) {
51474    event.preventDefault && event.preventDefault();
51475    event.preventManipulation && event.preventManipulation();
51476  },
51477      _hasTouchID = function _hasTouchID(list, ID) {
51478    var i = list.length;
51479
51480    while (i--) {
51481      if (list[i].identifier === ID) {
51482        return true;
51483      }
51484    }
51485  },
51486      _onMultiTouchDocumentEnd = function _onMultiTouchDocumentEnd(event) {
51487    _isMultiTouching = event.touches && _dragCount < event.touches.length;
51488
51489    _removeListener(event.target, "touchend", _onMultiTouchDocumentEnd);
51490  },
51491      _onMultiTouchDocument = function _onMultiTouchDocument(event) {
51492    _isMultiTouching = event.touches && _dragCount < event.touches.length;
51493
51494    _addListener(event.target, "touchend", _onMultiTouchDocumentEnd);
51495  },
51496      _getDocScrollTop$1 = function _getDocScrollTop(doc) {
51497    return _win$1.pageYOffset || doc.scrollTop || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
51498  },
51499      _getDocScrollLeft$1 = function _getDocScrollLeft(doc) {
51500    return _win$1.pageXOffset || doc.scrollLeft || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
51501  },
51502      _addScrollListener = function _addScrollListener(e, callback) {
51503    _addListener(e, "scroll", callback);
51504
51505    if (!_isRoot(e.parentNode)) {
51506      _addScrollListener(e.parentNode, callback);
51507    }
51508  },
51509      _removeScrollListener = function _removeScrollListener(e, callback) {
51510    _removeListener(e, "scroll", callback);
51511
51512    if (!_isRoot(e.parentNode)) {
51513      _removeScrollListener(e.parentNode, callback);
51514    }
51515  },
51516      _isRoot = function _isRoot(e) {
51517    return !!(!e || e === _docElement$1 || e.nodeType === 9 || e === _doc$1.body || e === _win$1 || !e.nodeType || !e.parentNode);
51518  },
51519      _getMaxScroll = function _getMaxScroll(element, axis) {
51520    var dim = axis === "x" ? "Width" : "Height",
51521        scroll = "scroll" + dim,
51522        client = "client" + dim;
51523    return Math.max(0, _isRoot(element) ? Math.max(_docElement$1[scroll], _body$1[scroll]) - (_win$1["inner" + dim] || _docElement$1[client] || _body$1[client]) : element[scroll] - element[client]);
51524  },
51525      _recordMaxScrolls = function _recordMaxScrolls(e, skipCurrent) {
51526    var x = _getMaxScroll(e, "x"),
51527        y = _getMaxScroll(e, "y");
51528
51529    if (_isRoot(e)) {
51530      e = _windowProxy;
51531    } else {
51532      _recordMaxScrolls(e.parentNode, skipCurrent);
51533    }
51534
51535    e._gsMaxScrollX = x;
51536    e._gsMaxScrollY = y;
51537
51538    if (!skipCurrent) {
51539      e._gsScrollX = e.scrollLeft || 0;
51540      e._gsScrollY = e.scrollTop || 0;
51541    }
51542  },
51543      _setStyle = function _setStyle(element, property, value) {
51544    var style = element.style;
51545
51546    if (!style) {
51547      return;
51548    }
51549
51550    if (_isUndefined(style[property])) {
51551      property = _checkPrefix(property, element) || property;
51552    }
51553
51554    if (value == null) {
51555      style.removeProperty && style.removeProperty(property.replace(/([A-Z])/g, "-$1").toLowerCase());
51556    } else {
51557      style[property] = value;
51558    }
51559  },
51560      _getComputedStyle = function _getComputedStyle(element) {
51561    return _win$1.getComputedStyle(element instanceof Element ? element : element.host || (element.parentNode || {}).host || element);
51562  },
51563      _tempRect = {},
51564      _parseRect = function _parseRect(e) {
51565    if (e === _win$1) {
51566      _tempRect.left = _tempRect.top = 0;
51567      _tempRect.width = _tempRect.right = _docElement$1.clientWidth || e.innerWidth || _body$1.clientWidth || 0;
51568      _tempRect.height = _tempRect.bottom = (e.innerHeight || 0) - 20 < _docElement$1.clientHeight ? _docElement$1.clientHeight : e.innerHeight || _body$1.clientHeight || 0;
51569      return _tempRect;
51570    }
51571
51572    var doc = e.ownerDocument || _doc$1,
51573        r = !_isUndefined(e.pageX) ? {
51574      left: e.pageX - _getDocScrollLeft$1(doc),
51575      top: e.pageY - _getDocScrollTop$1(doc),
51576      right: e.pageX - _getDocScrollLeft$1(doc) + 1,
51577      bottom: e.pageY - _getDocScrollTop$1(doc) + 1
51578    } : !e.nodeType && !_isUndefined(e.left) && !_isUndefined(e.top) ? e : _toArray(e)[0].getBoundingClientRect();
51579
51580    if (_isUndefined(r.right) && !_isUndefined(r.width)) {
51581      r.right = r.left + r.width;
51582      r.bottom = r.top + r.height;
51583    } else if (_isUndefined(r.width)) {
51584      r = {
51585        width: r.right - r.left,
51586        height: r.bottom - r.top,
51587        right: r.right,
51588        left: r.left,
51589        bottom: r.bottom,
51590        top: r.top
51591      };
51592    }
51593
51594    return r;
51595  },
51596      _dispatchEvent = function _dispatchEvent(target, type, callbackName) {
51597    var vars = target.vars,
51598        callback = vars[callbackName],
51599        listeners = target._listeners[type],
51600        result;
51601
51602    if (_isFunction(callback)) {
51603      result = callback.apply(vars.callbackScope || target, vars[callbackName + "Params"] || [target.pointerEvent]);
51604    }
51605
51606    if (listeners && target.dispatchEvent(type) === false) {
51607      result = false;
51608    }
51609
51610    return result;
51611  },
51612      _getBounds = function _getBounds(target, context) {
51613    var e = _toArray(target)[0],
51614        top,
51615        left,
51616        offset;
51617
51618    if (!e.nodeType && e !== _win$1) {
51619      if (!_isUndefined(target.left)) {
51620        offset = {
51621          x: 0,
51622          y: 0
51623        };
51624        return {
51625          left: target.left - offset.x,
51626          top: target.top - offset.y,
51627          width: target.width,
51628          height: target.height
51629        };
51630      }
51631
51632      left = target.min || target.minX || target.minRotation || 0;
51633      top = target.min || target.minY || 0;
51634      return {
51635        left: left,
51636        top: top,
51637        width: (target.max || target.maxX || target.maxRotation || 0) - left,
51638        height: (target.max || target.maxY || 0) - top
51639      };
51640    }
51641
51642    return _getElementBounds(e, context);
51643  },
51644      _point1 = {},
51645      _getElementBounds = function _getElementBounds(element, context) {
51646    context = _toArray(context)[0];
51647    var isSVG = element.getBBox && element.ownerSVGElement,
51648        doc = element.ownerDocument || _doc$1,
51649        left,
51650        right,
51651        top,
51652        bottom,
51653        matrix,
51654        p1,
51655        p2,
51656        p3,
51657        p4,
51658        bbox,
51659        width,
51660        height,
51661        cs;
51662
51663    if (element === _win$1) {
51664      top = _getDocScrollTop$1(doc);
51665      left = _getDocScrollLeft$1(doc);
51666      right = left + (doc.documentElement.clientWidth || element.innerWidth || doc.body.clientWidth || 0);
51667      bottom = top + ((element.innerHeight || 0) - 20 < doc.documentElement.clientHeight ? doc.documentElement.clientHeight : element.innerHeight || doc.body.clientHeight || 0);
51668    } else if (context === _win$1 || _isUndefined(context)) {
51669      return element.getBoundingClientRect();
51670    } else {
51671      left = top = 0;
51672
51673      if (isSVG) {
51674        bbox = element.getBBox();
51675        width = bbox.width;
51676        height = bbox.height;
51677      } else {
51678        if (element.viewBox && (bbox = element.viewBox.baseVal)) {
51679          left = bbox.x || 0;
51680          top = bbox.y || 0;
51681          width = bbox.width;
51682          height = bbox.height;
51683        }
51684
51685        if (!width) {
51686          cs = _getComputedStyle(element);
51687          bbox = cs.boxSizing === "border-box";
51688          width = (parseFloat(cs.width) || element.clientWidth || 0) + (bbox ? 0 : parseFloat(cs.borderLeftWidth) + parseFloat(cs.borderRightWidth));
51689          height = (parseFloat(cs.height) || element.clientHeight || 0) + (bbox ? 0 : parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth));
51690        }
51691      }
51692
51693      right = width;
51694      bottom = height;
51695    }
51696
51697    if (element === context) {
51698      return {
51699        left: left,
51700        top: top,
51701        width: right - left,
51702        height: bottom - top
51703      };
51704    }
51705
51706    matrix = getGlobalMatrix(context, true).multiply(getGlobalMatrix(element));
51707    p1 = matrix.apply({
51708      x: left,
51709      y: top
51710    });
51711    p2 = matrix.apply({
51712      x: right,
51713      y: top
51714    });
51715    p3 = matrix.apply({
51716      x: right,
51717      y: bottom
51718    });
51719    p4 = matrix.apply({
51720      x: left,
51721      y: bottom
51722    });
51723    left = Math.min(p1.x, p2.x, p3.x, p4.x);
51724    top = Math.min(p1.y, p2.y, p3.y, p4.y);
51725    return {
51726      left: left,
51727      top: top,
51728      width: Math.max(p1.x, p2.x, p3.x, p4.x) - left,
51729      height: Math.max(p1.y, p2.y, p3.y, p4.y) - top
51730    };
51731  },
51732      _parseInertia = function _parseInertia(draggable, snap, max, min, factor, forceZeroVelocity) {
51733    var vars = {},
51734        a,
51735        i,
51736        l;
51737
51738    if (snap) {
51739      if (factor !== 1 && snap instanceof Array) {
51740        vars.end = a = [];
51741        l = snap.length;
51742
51743        if (_isObject(snap[0])) {
51744          for (i = 0; i < l; i++) {
51745            a[i] = _copy(snap[i], factor);
51746          }
51747        } else {
51748          for (i = 0; i < l; i++) {
51749            a[i] = snap[i] * factor;
51750          }
51751        }
51752
51753        max += 1.1;
51754        min -= 1.1;
51755      } else if (_isFunction(snap)) {
51756        vars.end = function (value) {
51757          var result = snap.call(draggable, value),
51758              copy,
51759              p;
51760
51761          if (factor !== 1) {
51762            if (_isObject(result)) {
51763              copy = {};
51764
51765              for (p in result) {
51766                copy[p] = result[p] * factor;
51767              }
51768
51769              result = copy;
51770            } else {
51771              result *= factor;
51772            }
51773          }
51774
51775          return result;
51776        };
51777      } else {
51778        vars.end = snap;
51779      }
51780    }
51781
51782    if (max || max === 0) {
51783      vars.max = max;
51784    }
51785
51786    if (min || min === 0) {
51787      vars.min = min;
51788    }
51789
51790    if (forceZeroVelocity) {
51791      vars.velocity = 0;
51792    }
51793
51794    return vars;
51795  },
51796      _isClickable = function _isClickable(element) {
51797    var data;
51798    return !element || !element.getAttribute || element === _body$1 ? false : (data = element.getAttribute("data-clickable")) === "true" || data !== "false" && (_clickableTagExp.test(element.nodeName + "") || element.getAttribute("contentEditable") === "true") ? true : _isClickable(element.parentNode);
51799  },
51800      _setSelectable = function _setSelectable(elements, selectable) {
51801    var i = elements.length,
51802        e;
51803
51804    while (i--) {
51805      e = elements[i];
51806      e.ondragstart = e.onselectstart = selectable ? null : _emptyFunc;
51807      gsap.set(e, {
51808        lazy: true,
51809        userSelect: selectable ? "text" : "none"
51810      });
51811    }
51812  },
51813      _isFixed$1 = function _isFixed(element) {
51814    if (_getComputedStyle(element).position === "fixed") {
51815      return true;
51816    }
51817
51818    element = element.parentNode;
51819
51820    if (element && element.nodeType === 1) {
51821      return _isFixed(element);
51822    }
51823  },
51824      _supports3D,
51825      _addPaddingBR,
51826      ScrollProxy = function ScrollProxy(element, vars) {
51827    element = gsap.utils.toArray(element)[0];
51828    vars = vars || {};
51829    var content = document.createElement("div"),
51830        style = content.style,
51831        node = element.firstChild,
51832        offsetTop = 0,
51833        offsetLeft = 0,
51834        prevTop = element.scrollTop,
51835        prevLeft = element.scrollLeft,
51836        scrollWidth = element.scrollWidth,
51837        scrollHeight = element.scrollHeight,
51838        extraPadRight = 0,
51839        maxLeft = 0,
51840        maxTop = 0,
51841        elementWidth,
51842        elementHeight,
51843        contentHeight,
51844        nextNode,
51845        transformStart,
51846        transformEnd;
51847
51848    if (_supports3D && vars.force3D !== false) {
51849      transformStart = "translate3d(";
51850      transformEnd = "px,0px)";
51851    } else if (_transformProp$1) {
51852      transformStart = "translate(";
51853      transformEnd = "px)";
51854    }
51855
51856    this.scrollTop = function (value, force) {
51857      if (!arguments.length) {
51858        return -this.top();
51859      }
51860
51861      this.top(-value, force);
51862    };
51863
51864    this.scrollLeft = function (value, force) {
51865      if (!arguments.length) {
51866        return -this.left();
51867      }
51868
51869      this.left(-value, force);
51870    };
51871
51872    this.left = function (value, force) {
51873      if (!arguments.length) {
51874        return -(element.scrollLeft + offsetLeft);
51875      }
51876
51877      var dif = element.scrollLeft - prevLeft,
51878          oldOffset = offsetLeft;
51879
51880      if ((dif > 2 || dif < -2) && !force) {
51881        prevLeft = element.scrollLeft;
51882        gsap.killTweensOf(this, {
51883          left: 1,
51884          scrollLeft: 1
51885        });
51886        this.left(-prevLeft);
51887
51888        if (vars.onKill) {
51889          vars.onKill();
51890        }
51891
51892        return;
51893      }
51894
51895      value = -value;
51896
51897      if (value < 0) {
51898        offsetLeft = value - 0.5 | 0;
51899        value = 0;
51900      } else if (value > maxLeft) {
51901        offsetLeft = value - maxLeft | 0;
51902        value = maxLeft;
51903      } else {
51904        offsetLeft = 0;
51905      }
51906
51907      if (offsetLeft || oldOffset) {
51908        if (!this._skip) {
51909          style[_transformProp$1] = transformStart + -offsetLeft + "px," + -offsetTop + transformEnd;
51910        }
51911
51912        if (offsetLeft + extraPadRight >= 0) {
51913          style.paddingRight = offsetLeft + extraPadRight + "px";
51914        }
51915      }
51916
51917      element.scrollLeft = value | 0;
51918      prevLeft = element.scrollLeft;
51919    };
51920
51921    this.top = function (value, force) {
51922      if (!arguments.length) {
51923        return -(element.scrollTop + offsetTop);
51924      }
51925
51926      var dif = element.scrollTop - prevTop,
51927          oldOffset = offsetTop;
51928
51929      if ((dif > 2 || dif < -2) && !force) {
51930        prevTop = element.scrollTop;
51931        gsap.killTweensOf(this, {
51932          top: 1,
51933          scrollTop: 1
51934        });
51935        this.top(-prevTop);
51936
51937        if (vars.onKill) {
51938          vars.onKill();
51939        }
51940
51941        return;
51942      }
51943
51944      value = -value;
51945
51946      if (value < 0) {
51947        offsetTop = value - 0.5 | 0;
51948        value = 0;
51949      } else if (value > maxTop) {
51950        offsetTop = value - maxTop | 0;
51951        value = maxTop;
51952      } else {
51953        offsetTop = 0;
51954      }
51955
51956      if (offsetTop || oldOffset) {
51957        if (!this._skip) {
51958          style[_transformProp$1] = transformStart + -offsetLeft + "px," + -offsetTop + transformEnd;
51959        }
51960      }
51961
51962      element.scrollTop = value | 0;
51963      prevTop = element.scrollTop;
51964    };
51965
51966    this.maxScrollTop = function () {
51967      return maxTop;
51968    };
51969
51970    this.maxScrollLeft = function () {
51971      return maxLeft;
51972    };
51973
51974    this.disable = function () {
51975      node = content.firstChild;
51976
51977      while (node) {
51978        nextNode = node.nextSibling;
51979        element.appendChild(node);
51980        node = nextNode;
51981      }
51982
51983      if (element === content.parentNode) {
51984        element.removeChild(content);
51985      }
51986    };
51987
51988    this.enable = function () {
51989      node = element.firstChild;
51990
51991      if (node === content) {
51992        return;
51993      }
51994
51995      while (node) {
51996        nextNode = node.nextSibling;
51997        content.appendChild(node);
51998        node = nextNode;
51999      }
52000
52001      element.appendChild(content);
52002      this.calibrate();
52003    };
52004
52005    this.calibrate = function (force) {
52006      var widthMatches = element.clientWidth === elementWidth,
52007          cs,
52008          x,
52009          y;
52010      prevTop = element.scrollTop;
52011      prevLeft = element.scrollLeft;
52012
52013      if (widthMatches && element.clientHeight === elementHeight && content.offsetHeight === contentHeight && scrollWidth === element.scrollWidth && scrollHeight === element.scrollHeight && !force) {
52014        return;
52015      }
52016
52017      if (offsetTop || offsetLeft) {
52018        x = this.left();
52019        y = this.top();
52020        this.left(-element.scrollLeft);
52021        this.top(-element.scrollTop);
52022      }
52023
52024      cs = _getComputedStyle(element);
52025
52026      if (!widthMatches || force) {
52027        style.display = "block";
52028        style.width = "auto";
52029        style.paddingRight = "0px";
52030        extraPadRight = Math.max(0, element.scrollWidth - element.clientWidth);
52031
52032        if (extraPadRight) {
52033          extraPadRight += parseFloat(cs.paddingLeft) + (_addPaddingBR ? parseFloat(cs.paddingRight) : 0);
52034        }
52035      }
52036
52037      style.display = "inline-block";
52038      style.position = "relative";
52039      style.overflow = "visible";
52040      style.verticalAlign = "top";
52041      style.boxSizing = "content-box";
52042      style.width = "100%";
52043      style.paddingRight = extraPadRight + "px";
52044
52045      if (_addPaddingBR) {
52046        style.paddingBottom = cs.paddingBottom;
52047      }
52048
52049      elementWidth = element.clientWidth;
52050      elementHeight = element.clientHeight;
52051      scrollWidth = element.scrollWidth;
52052      scrollHeight = element.scrollHeight;
52053      maxLeft = element.scrollWidth - elementWidth;
52054      maxTop = element.scrollHeight - elementHeight;
52055      contentHeight = content.offsetHeight;
52056      style.display = "block";
52057
52058      if (x || y) {
52059        this.left(x);
52060        this.top(y);
52061      }
52062    };
52063
52064    this.content = content;
52065    this.element = element;
52066    this._skip = false;
52067    this.enable();
52068  },
52069      _initCore = function _initCore(required) {
52070    if (_windowExists() && document.body) {
52071      var nav = window && window.navigator;
52072      _win$1 = window;
52073      _doc$1 = document;
52074      _docElement$1 = _doc$1.documentElement;
52075      _body$1 = _doc$1.body;
52076      _tempDiv = _createElement("div");
52077      _supportsPointer = !!window.PointerEvent;
52078      _placeholderDiv = _createElement("div");
52079      _placeholderDiv.style.cssText = "visibility:hidden;height:1px;top:-1px;pointer-events:none;position:relative;clear:both;cursor:grab";
52080      _defaultCursor = _placeholderDiv.style.cursor === "grab" ? "grab" : "move";
52081      _isAndroid = nav && nav.userAgent.toLowerCase().indexOf("android") !== -1;
52082      _isTouchDevice = "ontouchstart" in _docElement$1 && "orientation" in _win$1 || nav && (nav.MaxTouchPoints > 0 || nav.msMaxTouchPoints > 0);
52083
52084      _addPaddingBR = function () {
52085        var div = _createElement("div"),
52086            child = _createElement("div"),
52087            childStyle = child.style,
52088            parent = _body$1,
52089            val;
52090
52091        childStyle.display = "inline-block";
52092        childStyle.position = "relative";
52093        div.style.cssText = "width:90px;height:40px;padding:10px;overflow:auto;visibility:hidden";
52094        div.appendChild(child);
52095        parent.appendChild(div);
52096        val = child.offsetHeight + 18 > div.scrollHeight;
52097        parent.removeChild(div);
52098        return val;
52099      }();
52100
52101      _touchEventLookup = function (types) {
52102        var standard = types.split(","),
52103            converted = ("onpointerdown" in _tempDiv ? "pointerdown,pointermove,pointerup,pointercancel" : "onmspointerdown" in _tempDiv ? "MSPointerDown,MSPointerMove,MSPointerUp,MSPointerCancel" : types).split(","),
52104            obj = {},
52105            i = 4;
52106
52107        while (--i > -1) {
52108          obj[standard[i]] = converted[i];
52109          obj[converted[i]] = standard[i];
52110        }
52111
52112        try {
52113          _docElement$1.addEventListener("test", null, Object.defineProperty({}, "passive", {
52114            get: function get() {
52115              _supportsPassive = 1;
52116            }
52117          }));
52118        } catch (e) {}
52119
52120        return obj;
52121      }("touchstart,touchmove,touchend,touchcancel");
52122
52123      _addListener(_doc$1, "touchcancel", _emptyFunc);
52124
52125      _addListener(_win$1, "touchmove", _emptyFunc);
52126
52127      _body$1 && _body$1.addEventListener("touchstart", _emptyFunc);
52128
52129      _addListener(_doc$1, "contextmenu", function () {
52130        for (var p in _lookup) {
52131          if (_lookup[p].isPressed) {
52132            _lookup[p].endDrag();
52133          }
52134        }
52135      });
52136
52137      gsap = _coreInitted = _getGSAP();
52138    }
52139
52140    if (gsap) {
52141      InertiaPlugin = gsap.plugins.inertia;
52142
52143      _context = gsap.core.context || function () {};
52144
52145      _checkPrefix = gsap.utils.checkPrefix;
52146      _transformProp$1 = _checkPrefix(_transformProp$1);
52147      _transformOriginProp$1 = _checkPrefix(_transformOriginProp$1);
52148      _toArray = gsap.utils.toArray;
52149      _getStyleSaver = gsap.core.getStyleSaver;
52150      _supports3D = !!_checkPrefix("perspective");
52151    } else if (required) {
52152      console.warn("Please gsap.registerPlugin(Draggable)");
52153    }
52154  };
52155
52156  var EventDispatcher = function () {
52157    function EventDispatcher(target) {
52158      this._listeners = {};
52159      this.target = target || this;
52160    }
52161
52162    var _proto = EventDispatcher.prototype;
52163
52164    _proto.addEventListener = function addEventListener(type, callback) {
52165      var list = this._listeners[type] || (this._listeners[type] = []);
52166
52167      if (!~list.indexOf(callback)) {
52168        list.push(callback);
52169      }
52170    };
52171
52172    _proto.removeEventListener = function removeEventListener(type, callback) {
52173      var list = this._listeners[type],
52174          i = list && list.indexOf(callback);
52175      i >= 0 && list.splice(i, 1);
52176    };
52177
52178    _proto.dispatchEvent = function dispatchEvent(type) {
52179      var _this = this;
52180
52181      var result;
52182      (this._listeners[type] || []).forEach(function (callback) {
52183        return callback.call(_this, {
52184          type: type,
52185          target: _this.target
52186        }) === false && (result = false);
52187      });
52188      return result;
52189    };
52190
52191    return EventDispatcher;
52192  }();
52193
52194  var Draggable = function (_EventDispatcher) {
52195    _inheritsLoose(Draggable, _EventDispatcher);
52196
52197    function Draggable(target, vars) {
52198      var _this2;
52199
52200      _this2 = _EventDispatcher.call(this) || this;
52201      _coreInitted || _initCore(1);
52202      target = _toArray(target)[0];
52203      _this2.styles = _getStyleSaver && _getStyleSaver(target, "transform,left,top");
52204
52205      if (!InertiaPlugin) {
52206        InertiaPlugin = gsap.plugins.inertia;
52207      }
52208
52209      _this2.vars = vars = _copy(vars || {});
52210      _this2.target = target;
52211      _this2.x = _this2.y = _this2.rotation = 0;
52212      _this2.dragResistance = parseFloat(vars.dragResistance) || 0;
52213      _this2.edgeResistance = isNaN(vars.edgeResistance) ? 1 : parseFloat(vars.edgeResistance) || 0;
52214      _this2.lockAxis = vars.lockAxis;
52215      _this2.autoScroll = vars.autoScroll || 0;
52216      _this2.lockedAxis = null;
52217      _this2.allowEventDefault = !!vars.allowEventDefault;
52218      gsap.getProperty(target, "x");
52219
52220      var type = (vars.type || "x,y").toLowerCase(),
52221          xyMode = ~type.indexOf("x") || ~type.indexOf("y"),
52222          rotationMode = type.indexOf("rotation") !== -1,
52223          xProp = rotationMode ? "rotation" : xyMode ? "x" : "left",
52224          yProp = xyMode ? "y" : "top",
52225          allowX = !!(~type.indexOf("x") || ~type.indexOf("left") || type === "scroll"),
52226          allowY = !!(~type.indexOf("y") || ~type.indexOf("top") || type === "scroll"),
52227          minimumMovement = vars.minimumMovement || 2,
52228          self = _assertThisInitialized(_this2),
52229          triggers = _toArray(vars.trigger || vars.handle || target),
52230          killProps = {},
52231          dragEndTime = 0,
52232          checkAutoScrollBounds = false,
52233          autoScrollMarginTop = vars.autoScrollMarginTop || 40,
52234          autoScrollMarginRight = vars.autoScrollMarginRight || 40,
52235          autoScrollMarginBottom = vars.autoScrollMarginBottom || 40,
52236          autoScrollMarginLeft = vars.autoScrollMarginLeft || 40,
52237          isClickable = vars.clickableTest || _isClickable,
52238          clickTime = 0,
52239          gsCache = target._gsap || gsap.core.getCache(target),
52240          isFixed = _isFixed$1(target),
52241          getPropAsNum = function getPropAsNum(property, unit) {
52242        return parseFloat(gsCache.get(target, property, unit));
52243      },
52244          ownerDoc = target.ownerDocument || _doc$1,
52245          enabled,
52246          scrollProxy,
52247          startPointerX,
52248          startPointerY,
52249          startElementX,
52250          startElementY,
52251          hasBounds,
52252          hasDragCallback,
52253          hasMoveCallback,
52254          maxX,
52255          minX,
52256          maxY,
52257          minY,
52258          touch,
52259          touchID,
52260          rotationOrigin,
52261          dirty,
52262          old,
52263          snapX,
52264          snapY,
52265          snapXY,
52266          isClicking,
52267          touchEventTarget,
52268          matrix,
52269          interrupted,
52270          allowNativeTouchScrolling,
52271          touchDragAxis,
52272          isDispatching,
52273          clickDispatch,
52274          trustedClickDispatch,
52275          isPreventingDefault,
52276          innerMatrix,
52277          dragged,
52278          onContextMenu = function onContextMenu(e) {
52279        _preventDefault(e);
52280
52281        e.stopImmediatePropagation && e.stopImmediatePropagation();
52282        return false;
52283      },
52284          render = function render(suppressEvents) {
52285        if (self.autoScroll && self.isDragging && (checkAutoScrollBounds || dirty)) {
52286          var e = target,
52287              autoScrollFactor = self.autoScroll * 15,
52288              parent,
52289              isRoot,
52290              rect,
52291              pointerX,
52292              pointerY,
52293              changeX,
52294              changeY,
52295              gap;
52296          checkAutoScrollBounds = false;
52297          _windowProxy.scrollTop = _win$1.pageYOffset != null ? _win$1.pageYOffset : ownerDoc.documentElement.scrollTop != null ? ownerDoc.documentElement.scrollTop : ownerDoc.body.scrollTop;
52298          _windowProxy.scrollLeft = _win$1.pageXOffset != null ? _win$1.pageXOffset : ownerDoc.documentElement.scrollLeft != null ? ownerDoc.documentElement.scrollLeft : ownerDoc.body.scrollLeft;
52299          pointerX = self.pointerX - _windowProxy.scrollLeft;
52300          pointerY = self.pointerY - _windowProxy.scrollTop;
52301
52302          while (e && !isRoot) {
52303            isRoot = _isRoot(e.parentNode);
52304            parent = isRoot ? _windowProxy : e.parentNode;
52305            rect = isRoot ? {
52306              bottom: Math.max(_docElement$1.clientHeight, _win$1.innerHeight || 0),
52307              right: Math.max(_docElement$1.clientWidth, _win$1.innerWidth || 0),
52308              left: 0,
52309              top: 0
52310            } : parent.getBoundingClientRect();
52311            changeX = changeY = 0;
52312
52313            if (allowY) {
52314              gap = parent._gsMaxScrollY - parent.scrollTop;
52315
52316              if (gap < 0) {
52317                changeY = gap;
52318              } else if (pointerY > rect.bottom - autoScrollMarginBottom && gap) {
52319                checkAutoScrollBounds = true;
52320                changeY = Math.min(gap, autoScrollFactor * (1 - Math.max(0, rect.bottom - pointerY) / autoScrollMarginBottom) | 0);
52321              } else if (pointerY < rect.top + autoScrollMarginTop && parent.scrollTop) {
52322                checkAutoScrollBounds = true;
52323                changeY = -Math.min(parent.scrollTop, autoScrollFactor * (1 - Math.max(0, pointerY - rect.top) / autoScrollMarginTop) | 0);
52324              }
52325
52326              if (changeY) {
52327                parent.scrollTop += changeY;
52328              }
52329            }
52330
52331            if (allowX) {
52332              gap = parent._gsMaxScrollX - parent.scrollLeft;
52333
52334              if (gap < 0) {
52335                changeX = gap;
52336              } else if (pointerX > rect.right - autoScrollMarginRight && gap) {
52337                checkAutoScrollBounds = true;
52338                changeX = Math.min(gap, autoScrollFactor * (1 - Math.max(0, rect.right - pointerX) / autoScrollMarginRight) | 0);
52339              } else if (pointerX < rect.left + autoScrollMarginLeft && parent.scrollLeft) {
52340                checkAutoScrollBounds = true;
52341                changeX = -Math.min(parent.scrollLeft, autoScrollFactor * (1 - Math.max(0, pointerX - rect.left) / autoScrollMarginLeft) | 0);
52342              }
52343
52344              if (changeX) {
52345                parent.scrollLeft += changeX;
52346              }
52347            }
52348
52349            if (isRoot && (changeX || changeY)) {
52350              _win$1.scrollTo(parent.scrollLeft, parent.scrollTop);
52351
52352              setPointerPosition(self.pointerX + changeX, self.pointerY + changeY);
52353            }
52354
52355            e = parent;
52356          }
52357        }
52358
52359        if (dirty) {
52360          var x = self.x,
52361              y = self.y;
52362
52363          if (rotationMode) {
52364            self.deltaX = x - parseFloat(gsCache.rotation);
52365            self.rotation = x;
52366            gsCache.rotation = x + "deg";
52367            gsCache.renderTransform(1, gsCache);
52368          } else {
52369            if (scrollProxy) {
52370              if (allowY) {
52371                self.deltaY = y - scrollProxy.top();
52372                scrollProxy.top(y);
52373              }
52374
52375              if (allowX) {
52376                self.deltaX = x - scrollProxy.left();
52377                scrollProxy.left(x);
52378              }
52379            } else if (xyMode) {
52380              if (allowY) {
52381                self.deltaY = y - parseFloat(gsCache.y);
52382                gsCache.y = y + "px";
52383              }
52384
52385              if (allowX) {
52386                self.deltaX = x - parseFloat(gsCache.x);
52387                gsCache.x = x + "px";
52388              }
52389
52390              gsCache.renderTransform(1, gsCache);
52391            } else {
52392              if (allowY) {
52393                self.deltaY = y - parseFloat(target.style.top || 0);
52394                target.style.top = y + "px";
52395              }
52396
52397              if (allowX) {
52398                self.deltaX = x - parseFloat(target.style.left || 0);
52399                target.style.left = x + "px";
52400              }
52401            }
52402          }
52403
52404          if (hasDragCallback && !suppressEvents && !isDispatching) {
52405            isDispatching = true;
52406
52407            if (_dispatchEvent(self, "drag", "onDrag") === false) {
52408              if (allowX) {
52409                self.x -= self.deltaX;
52410              }
52411
52412              if (allowY) {
52413                self.y -= self.deltaY;
52414              }
52415
52416              render(true);
52417            }
52418
52419            isDispatching = false;
52420          }
52421        }
52422
52423        dirty = false;
52424      },
52425          syncXY = function syncXY(skipOnUpdate, skipSnap) {
52426        var x = self.x,
52427            y = self.y,
52428            snappedValue,
52429            cs;
52430
52431        if (!target._gsap) {
52432          gsCache = gsap.core.getCache(target);
52433        }
52434
52435        gsCache.uncache && gsap.getProperty(target, "x");
52436
52437        if (xyMode) {
52438          self.x = parseFloat(gsCache.x);
52439          self.y = parseFloat(gsCache.y);
52440        } else if (rotationMode) {
52441          self.x = self.rotation = 
52441parseFloat(gsCache.rotation
vendor: 18,327 bytes, lines 52441-52991
52441);
52442        } else if (scrollProxy) {
52443          self.y = scrollProxy.top();
52444          self.x = scrollProxy.left();
52445        } else {
52446          self.y = parseFloat(target.style.top || (cs = _getComputedStyle(target)) && cs.top) || 0;
52447          self.x = parseFloat(target.style.left || (cs || {}).left) || 0;
52448        }
52449
52450        if ((snapX || snapY || snapXY) && !skipSnap && (self.isDragging || self.isThrowing)) {
52451          if (snapXY) {
52452            _temp1.x = self.x;
52453            _temp1.y = self.y;
52454            snappedValue = snapXY(_temp1);
52455
52456            if (snappedValue.x !== self.x) {
52457              self.x = snappedValue.x;
52458              dirty = true;
52459            }
52460
52461            if (snappedValue.y !== self.y) {
52462              self.y = snappedValue.y;
52463              dirty = true;
52464            }
52465          }
52466
52467          if (snapX) {
52468            snappedValue = snapX(self.x);
52469
52470            if (snappedValue !== self.x) {
52471              self.x = snappedValue;
52472
52473              if (rotationMode) {
52474                self.rotation = snappedValue;
52475              }
52476
52477              dirty = true;
52478            }
52479          }
52480
52481          if (snapY) {
52482            snappedValue = snapY(self.y);
52483
52484            if (snappedValue !== self.y) {
52485              self.y = snappedValue;
52486            }
52487
52488            dirty = true;
52489          }
52490        }
52491
52492        dirty && render(true);
52493
52494        if (!skipOnUpdate) {
52495          self.deltaX = self.x - x;
52496          self.deltaY = self.y - y;
52497
52498          _dispatchEvent(self, "throwupdate", "onThrowUpdate");
52499        }
52500      },
52501          buildSnapFunc = function buildSnapFunc(snap, min, max, factor) {
52502        if (min == null) {
52503          min = -_bigNum;
52504        }
52505
52506        if (max == null) {
52507          max = _bigNum;
52508        }
52509
52510        if (_isFunction(snap)) {
52511          return function (n) {
52512            var edgeTolerance = !self.isPressed ? 1 : 1 - self.edgeResistance;
52513            return snap.call(self, (n > max ? max + (n - max) * edgeTolerance : n < min ? min + (n - min) * edgeTolerance : n) * factor) * factor;
52514          };
52515        }
52516
52517        if (_isArray(snap)) {
52518          return function (n) {
52519            var i = snap.length,
52520                closest = 0,
52521                absDif = _bigNum,
52522                val,
52523                dif;
52524
52525            while (--i > -1) {
52526              val = snap[i];
52527              dif = val - n;
52528
52529              if (dif < 0) {
52530                dif = -dif;
52531              }
52532
52533              if (dif < absDif && val >= min && val <= max) {
52534                closest = i;
52535                absDif = dif;
52536              }
52537            }
52538
52539            return snap[closest];
52540          };
52541        }
52542
52543        return isNaN(snap) ? function (n) {
52544          return n;
52545        } : function () {
52546          return snap * factor;
52547        };
52548      },
52549          buildPointSnapFunc = function buildPointSnapFunc(snap, minX, maxX, minY, maxY, radius, factor) {
52550        radius = radius && radius < _bigNum ? radius * radius : _bigNum;
52551
52552        if (_isFunction(snap)) {
52553          return function (point) {
52554            var edgeTolerance = !self.isPressed ? 1 : 1 - self.edgeResistance,
52555                x = point.x,
52556                y = point.y,
52557                result,
52558                dx,
52559                dy;
52560            point.x = x = x > maxX ? maxX + (x - maxX) * edgeTolerance : x < minX ? minX + (x - minX) * edgeTolerance : x;
52561            point.y = y = y > maxY ? maxY + (y - maxY) * edgeTolerance : y < minY ? minY + (y - minY) * edgeTolerance : y;
52562            result = snap.call(self, point);
52563
52564            if (result !== point) {
52565              point.x = result.x;
52566              point.y = result.y;
52567            }
52568
52569            if (factor !== 1) {
52570              point.x *= factor;
52571              point.y *= factor;
52572            }
52573
52574            if (radius < _bigNum) {
52575              dx = point.x - x;
52576              dy = point.y - y;
52577
52578              if (dx * dx + dy * dy > radius) {
52579                point.x = x;
52580                point.y = y;
52581              }
52582            }
52583
52584            return point;
52585          };
52586        }
52587
52588        if (_isArray(snap)) {
52589          return function (p) {
52590            var i = snap.length,
52591                closest = 0,
52592                minDist = _bigNum,
52593                x,
52594                y,
52595                point,
52596                dist;
52597
52598            while (--i > -1) {
52599              point = snap[i];
52600              x = point.x - p.x;
52601              y = point.y - p.y;
52602              dist = x * x + y * y;
52603
52604              if (dist < minDist) {
52605                closest = i;
52606                minDist = dist;
52607              }
52608            }
52609
52610            return minDist <= radius ? snap[closest] : p;
52611          };
52612        }
52613
52614        return function (n) {
52615          return n;
52616        };
52617      },
52618          calculateBounds = function calculateBounds() {
52619        var bounds, targetBounds, snap, snapIsRaw;
52620        hasBounds = false;
52621
52622        if (scrollProxy) {
52623          scrollProxy.calibrate();
52624          self.minX = minX = -scrollProxy.maxScrollLeft();
52625          self.minY = minY = -scrollProxy.maxScrollTop();
52626          self.maxX = maxX = self.maxY = maxY = 0;
52627          hasBounds = true;
52628        } else if (!!vars.bounds) {
52629          bounds = _getBounds(vars.bounds, target.parentNode);
52630
52631          if (rotationMode) {
52632            self.minX = minX = bounds.left;
52633            self.maxX = maxX = bounds.left + bounds.width;
52634            self.minY = minY = self.maxY = maxY = 0;
52635          } else if (!_isUndefined(vars.bounds.maxX) || !_isUndefined(vars.bounds.maxY)) {
52636            bounds = vars.bounds;
52637            self.minX = minX = bounds.minX;
52638            self.minY = minY = bounds.minY;
52639            self.maxX = maxX = bounds.maxX;
52640            self.maxY = maxY = bounds.maxY;
52641          } else {
52642            targetBounds = _getBounds(target, target.parentNode);
52643            self.minX = minX = Math.round(getPropAsNum(xProp, "px") + bounds.left - targetBounds.left);
52644            self.minY = minY = Math.round(getPropAsNum(yProp, "px") + bounds.top - targetBounds.top);
52645            self.maxX = maxX = Math.round(minX + (bounds.width - targetBounds.width));
52646            self.maxY = maxY = Math.round(minY + (bounds.height - targetBounds.height));
52647          }
52648
52649          if (minX > maxX) {
52650            self.minX = maxX;
52651            self.maxX = maxX = minX;
52652            minX = self.minX;
52653          }
52654
52655          if (minY > maxY) {
52656            self.minY = maxY;
52657            self.maxY = maxY = minY;
52658            minY = self.minY;
52659          }
52660
52661          if (rotationMode) {
52662            self.minRotation = minX;
52663            self.maxRotation = maxX;
52664          }
52665
52666          hasBounds = true;
52667        }
52668
52669        if (vars.liveSnap) {
52670          snap = vars.liveSnap === true ? vars.snap || {} : vars.liveSnap;
52671          snapIsRaw = _isArray(snap) || _isFunction(snap);
52672
52673          if (rotationMode) {
52674            snapX = buildSnapFunc(snapIsRaw ? snap : snap.rotation, minX, maxX, 1);
52675            snapY = null;
52676          } else {
52677            if (snap.points) {
52678              snapXY = buildPointSnapFunc(snapIsRaw ? snap : snap.points, minX, maxX, minY, maxY, snap.radius, scrollProxy ? -1 : 1);
52679            } else {
52680              if (allowX) {
52681                snapX = buildSnapFunc(snapIsRaw ? snap : snap.x || snap.left || snap.scrollLeft, minX, maxX, scrollProxy ? -1 : 1);
52682              }
52683
52684              if (allowY) {
52685                snapY = buildSnapFunc(snapIsRaw ? snap : snap.y || snap.top || snap.scrollTop, minY, maxY, scrollProxy ? -1 : 1);
52686              }
52687            }
52688          }
52689        }
52690      },
52691          onThrowComplete = function onThrowComplete() {
52692        self.isThrowing = false;
52693
52694        _dispatchEvent(self, "throwcomplete", "onThrowComplete");
52695      },
52696          onThrowInterrupt = function onThrowInterrupt() {
52697        self.isThrowing = false;
52698      },
52699          animate = function animate(inertia, forceZeroVelocity) {
52700        var snap, snapIsRaw, tween, overshootTolerance;
52701
52702        if (inertia && InertiaPlugin) {
52703          if (inertia === true) {
52704            snap = vars.snap || vars.liveSnap || {};
52705            snapIsRaw = _isArray(snap) || _isFunction(snap);
52706            inertia = {
52707              resistance: (vars.throwResistance || vars.resistance || 1000) / (rotationMode ? 10 : 1)
52708            };
52709
52710            if (rotationMode) {
52711              inertia.rotation = _parseInertia(self, snapIsRaw ? snap : snap.rotation, maxX, minX, 1, forceZeroVelocity);
52712            } else {
52713              if (allowX) {
52714                inertia[xProp] = _parseInertia(self, snapIsRaw ? snap : snap.points || snap.x || snap.left, maxX, minX, scrollProxy ? -1 : 1, forceZeroVelocity || self.lockedAxis === "x");
52715              }
52716
52717              if (allowY) {
52718                inertia[yProp] = _parseInertia(self, snapIsRaw ? snap : snap.points || snap.y || snap.top, maxY, minY, scrollProxy ? -1 : 1, forceZeroVelocity || self.lockedAxis === "y");
52719              }
52720
52721              if (snap.points || _isArray(snap) && _isObject(snap[0])) {
52722                inertia.linkedProps = xProp + "," + yProp;
52723                inertia.radius = snap.radius;
52724              }
52725            }
52726          }
52727
52728          self.isThrowing = true;
52729          overshootTolerance = !isNaN(vars.overshootTolerance) ? vars.overshootTolerance : vars.edgeResistance === 1 ? 0 : 1 - self.edgeResistance + 0.2;
52730
52731          if (!inertia.duration) {
52732            inertia.duration = {
52733              max: Math.max(vars.minDuration || 0, "maxDuration" in vars ? vars.maxDuration : 2),
52734              min: !isNaN(vars.minDuration) ? vars.minDuration : overshootTolerance === 0 || _isObject(inertia) && inertia.resistance > 1000 ? 0 : 0.5,
52735              overshoot: overshootTolerance
52736            };
52737          }
52738
52739          self.tween = tween = gsap.to(scrollProxy || target, {
52740            inertia: inertia,
52741            data: "_draggable",
52742            inherit: false,
52743            onComplete: onThrowComplete,
52744            onInterrupt: onThrowInterrupt,
52745            onUpdate: vars.fastMode ? _dispatchEvent : syncXY,
52746            onUpdateParams: vars.fastMode ? [self, "onthrowupdate", "onThrowUpdate"] : snap && snap.radius ? [false, true] : []
52747          });
52748
52749          if (!vars.fastMode) {
52750            if (scrollProxy) {
52751              scrollProxy._skip = true;
52752            }
52753
52754            tween.render(1e9, true, true);
52755            syncXY(true, true);
52756            self.endX = self.x;
52757            self.endY = self.y;
52758
52759            if (rotationMode) {
52760              self.endRotation = self.x;
52761            }
52762
52763            tween.play(0);
52764            syncXY(true, true);
52765
52766            if (scrollProxy) {
52767              scrollProxy._skip = false;
52768            }
52769          }
52770        } else if (hasBounds) {
52771          self.applyBounds();
52772        }
52773      },
52774          updateMatrix = function updateMatrix(shiftStart) {
52775        var start = matrix,
52776            p;
52777        matrix = getGlobalMatrix(target.parentNode, true);
52778
52779        if (shiftStart && self.isPressed && !matrix.equals(start || new Matrix2D())) {
52780          p = start.inverse().apply({
52781            x: startPointerX,
52782            y: startPointerY
52783          });
52784          matrix.apply(p, p);
52785          startPointerX = p.x;
52786          startPointerY = p.y;
52787        }
52788
52789        if (matrix.equals(_identityMatrix$1)) {
52790          matrix = null;
52791        }
52792      },
52793          recordStartPositions = function recordStartPositions() {
52794        var edgeTolerance = 1 - self.edgeResistance,
52795            offsetX = isFixed ? _getDocScrollLeft$1(ownerDoc) : 0,
52796            offsetY = isFixed ? _getDocScrollTop$1(ownerDoc) : 0,
52797            parsedOrigin,
52798            x,
52799            y;
52800
52801        if (xyMode) {
52802          gsCache.x = getPropAsNum(xProp, "px") + "px";
52803          gsCache.y = getPropAsNum(yProp, "px") + "px";
52804          gsCache.renderTransform();
52805        }
52806
52807        updateMatrix(false);
52808        _point1.x = self.pointerX - offsetX;
52809        _point1.y = self.pointerY - offsetY;
52810        matrix && matrix.apply(_point1, _point1);
52811        startPointerX = _point1.x;
52812        startPointerY = _point1.y;
52813
52814        if (dirty) {
52815          setPointerPosition(self.pointerX, self.pointerY);
52816          render(true);
52817        }
52818
52819        innerMatrix = getGlobalMatrix(target);
52820
52821        if (scrollProxy) {
52822          calculateBounds();
52823          startElementY = scrollProxy.top();
52824          startElementX = scrollProxy.left();
52825        } else {
52826          if (isTweening()) {
52827            syncXY(true, true);
52828            calculateBounds();
52829          } else {
52830            self.applyBounds();
52831          }
52832
52833          if (rotationMode) {
52834            parsedOrigin = target.ownerSVGElement ? [gsCache.xOrigin - target.getBBox().x, gsCache.yOrigin - target.getBBox().y] : (_getComputedStyle(target)[_transformOriginProp$1] || "0 0").split(" ");
52835            rotationOrigin = self.rotationOrigin = getGlobalMatrix(target).apply({
52836              x: parseFloat(parsedOrigin[0]) || 0,
52837              y: parseFloat(parsedOrigin[1]) || 0
52838            });
52839            syncXY(true, true);
52840            x = self.pointerX - rotationOrigin.x - offsetX;
52841            y = rotationOrigin.y - self.pointerY + offsetY;
52842            startElementX = self.x;
52843            startElementY = self.y = Math.atan2(y, x) * _RAD2DEG;
52844          } else {
52845            startElementY = getPropAsNum(yProp, "px");
52846            startElementX = getPropAsNum(xProp, "px");
52847          }
52848        }
52849
52850        if (hasBounds && edgeTolerance) {
52851          if (startElementX > maxX) {
52852            startElementX = maxX + (startElementX - maxX) / edgeTolerance;
52853          } else if (startElementX < minX) {
52854            startElementX = minX - (minX - startElementX) / edgeTolerance;
52855          }
52856
52857          if (!rotationMode) {
52858            if (startElementY > maxY) {
52859              startElementY = maxY + (startElementY - maxY) / edgeTolerance;
52860            } else if (startElementY < minY) {
52861              startElementY = minY - (minY - startElementY) / edgeTolerance;
52862            }
52863          }
52864        }
52865
52866        self.startX = startElementX = _round(startElementX);
52867        self.startY = startElementY = _round(startElementY);
52868      },
52869          isTweening = function isTweening() {
52870        return self.tween && self.tween.isActive();
52871      },
52872          removePlaceholder = function removePlaceholder() {
52873        if (_placeholderDiv.parentNode && !isTweening() && !self.isDragging) {
52874          _placeholderDiv.parentNode.removeChild(_placeholderDiv);
52875        }
52876      },
52877          onPress = function onPress(e, force) {
52878        var i;
52879
52880        if (!enabled || self.isPressed || !e || (e.type === "mousedown" || e.type === "pointerdown") && !force && _getTime() - clickTime < 30 && _touchEventLookup[self.pointerEvent.type]) {
52881          isPreventingDefault && e && enabled && _preventDefault(e);
52882          return;
52883        }
52884
52885        interrupted = isTweening();
52886        dragged = false;
52887        self.pointerEvent = e;
52888
52889        if (_touchEventLookup[e.type]) {
52890          touchEventTarget = ~e.type.indexOf("touch") ? e.currentTarget || e.target : ownerDoc;
52891
52892          _addListener(touchEventTarget, "touchend", onRelease);
52893
52894          _addListener(touchEventTarget, "touchmove", onMove);
52895
52896          _addListener(touchEventTarget, "touchcancel", onRelease);
52897
52898          _addListener(ownerDoc, "touchstart", _onMultiTouchDocument);
52899        } else {
52900          touchEventTarget = null;
52901
52902          _addListener(ownerDoc, "mousemove", onMove);
52903        }
52904
52905        touchDragAxis = null;
52906
52907        if (!_supportsPointer || !touchEventTarget) {
52908          _addListener(ownerDoc, "mouseup", onRelease);
52909
52910          e && e.target && _addListener(e.target, "mouseup", onRelease);
52911        }
52912
52913        isClicking = isClickable.call(self, e.target) && vars.dragClickables === false && !force;
52914
52915        if (isClicking) {
52916          _addListener(e.target, "change", onRelease);
52917
52918          _dispatchEvent(self, "pressInit", "onPressInit");
52919
52920          _dispatchEvent(self, "press", "onPress");
52921
52922          _setSelectable(triggers, true);
52923
52924          isPreventingDefault = false;
52925          return;
52926        }
52927
52928        allowNativeTouchScrolling = !touchEventTarget || allowX === allowY || self.vars.allowNativeTouchScrolling === false || self.vars.allowContextMenu && e && (e.ctrlKey || e.which > 2) ? false : allowX ? "y" : "x";
52929        isPreventingDefault = !allowNativeTouchScrolling && !self.allowEventDefault;
52930
52931        if (isPreventingDefault) {
52932          _preventDefault(e);
52933
52934          _addListener(_win$1, "touchforcechange", _preventDefault);
52935        }
52936
52937        if (e.changedTouches) {
52938          e = touch = e.changedTouches[0];
52939          touchID = e.identifier;
52940        } else if (e.pointerId) {
52941          touchID = e.pointerId;
52942        } else {
52943          touch = touchID = null;
52944        }
52945
52946        _dragCount++;
52947
52948        _addToRenderQueue(render);
52949
52950        startPointerY = self.pointerY = e.pageY;
52951        startPointerX = self.pointerX = e.pageX;
52952
52953        _dispatchEvent(self, "pressInit", "onPressInit");
52954
52955        if (allowNativeTouchScrolling || self.autoScroll) {
52956          _recordMaxScrolls(target.parentNode);
52957        }
52958
52959        if (target.parentNode && self.autoScroll && !scrollProxy && !rotationMode && target.parentNode._gsMaxScrollX && !_placeholderDiv.parentNode && !target.getBBox) {
52960          _placeholderDiv.style.width = target.parentNode.scrollWidth + "px";
52961          target.parentNode.appendChild(_placeholderDiv);
52962        }
52963
52964        recordStartPositions();
52965        self.tween && self.tween.kill();
52966        self.isThrowing = false;
52967        gsap.killTweensOf(scrollProxy || target, killProps, true);
52968        scrollProxy && gsap.killTweensOf(target, {
52969          scrollTo: 1
52970        }, true);
52971        self.tween = self.lockedAxis = null;
52972
52973        if (vars.zIndexBoost || !rotationMode && !scrollProxy && vars.zIndexBoost !== false) {
52974          target.style.zIndex = Draggable.zIndex++;
52975        }
52976
52977        self.isPressed = true;
52978        hasDragCallback = !!(vars.onDrag || self._listeners.drag);
52979        hasMoveCallback = !!(vars.onMove || self._listeners.move);
52980
52981        if (vars.cursor !== false || vars.activeCursor) {
52982          i = triggers.length;
52983
52984          while (--i > -1) {
52985            gsap.set(triggers[i], {
52986              cursor: vars.activeCursor || vars.cursor || (_defaultCursor === "grab" ? "grabbing" : _defaultCursor)
52987            });
52988          }
52989        }
52990
52991        _dispatchEvent(self, "press", "onPress");
vendor: 2,447 bytes, lines 52992-53059
52992      },
52993          onMove = function onMove(e) {
52994        var originalEvent = e,
52995            touches,
52996            pointerX,
52997            pointerY,
52998            i,
52999            dx,
53000            dy;
53001
53002        if (!enabled || _isMultiTouching || !self.isPressed || !e) {
53003          isPreventingDefault && e && enabled && _preventDefault(e);
53004          return;
53005        }
53006
53007        self.pointerEvent = e;
53008        touches = e.changedTouches;
53009
53010        if (touches) {
53011          e = touches[0];
53012
53013          if (e !== touch && e.identifier !== touchID) {
53014            i = touches.length;
53015
53016            while (--i > -1 && (e = touches[i]).identifier !== touchID && e.target !== target) {}
53017
53018            if (i < 0) {
53019              return;
53020            }
53021          }
53022        } else if (e.pointerId && touchID && e.pointerId !== touchID) {
53023          return;
53024        }
53025
53026        if (touchEventTarget && allowNativeTouchScrolling && !touchDragAxis) {
53027          _point1.x = e.pageX - (isFixed ? _getDocScrollLeft$1(ownerDoc) : 0);
53028          _point1.y = e.pageY - (isFixed ? _getDocScrollTop$1(ownerDoc) : 0);
53029          matrix && matrix.apply(_point1, _point1);
53030          pointerX = _point1.x;
53031          pointerY = _point1.y;
53032          dx = Math.abs(pointerX - startPointerX);
53033          dy = Math.abs(pointerY - startPointerY);
53034
53035          if (dx !== dy && (dx > minimumMovement || dy > minimumMovement) || _isAndroid && allowNativeTouchScrolling === touchDragAxis) {
53036            touchDragAxis = dx > dy && allowX ? "x" : "y";
53037
53038            if (allowNativeTouchScrolling && touchDragAxis !== allowNativeTouchScrolling) {
53039              _addListener(_win$1, "touchforcechange", _preventDefault);
53040            }
53041
53042            if (self.vars.lockAxisOnTouchScroll !== false && allowX && allowY) {
53043              self.lockedAxis = touchDragAxis === "x" ? "y" : "x";
53044              _isFunction(self.vars.onLockAxis) && self.vars.onLockAxis.call(self, originalEvent);
53045            }
53046
53047            if (_isAndroid && allowNativeTouchScrolling === touchDragAxis) {
53048              onRelease(originalEvent);
53049              return;
53050            }
53051          }
53052        }
53053
53054        if (!self.allowEventDefault && (!allowNativeTouchScrolling || touchDragAxis && allowNativeTouchScrolling !== touchDragAxis) && originalEvent.cancelable !== false) {
53055          _preventDefault(originalEvent);
53056
53057          isPreventingDefault = true;
53058        } else if (isPreventingDefault) {
53059          isPreventingDefault = false;
vendor: 3,917 bytes, lines 53060-53188
53060        }
53061
53062        if (self.autoScroll) {
53063          checkAutoScrollBounds = true;
53064        }
53065
53066        setPointerPosition(e.pageX, e.pageY, hasMoveCallback);
53067      },
53068          setPointerPosition = function setPointerPosition(pointerX, pointerY, invokeOnMove) {
53069        var dragTolerance = 1 - self.dragResistance,
53070            edgeTolerance = 1 - self.edgeResistance,
53071            prevPointerX = self.pointerX,
53072            prevPointerY = self.pointerY,
53073            prevStartElementY = startElementY,
53074            prevX = self.x,
53075            prevY = self.y,
53076            prevEndX = self.endX,
53077            prevEndY = self.endY,
53078            prevEndRotation = self.endRotation,
53079            prevDirty = dirty,
53080            xChange,
53081            yChange,
53082            x,
53083            y,
53084            dif,
53085            temp;
53086        self.pointerX = pointerX;
53087        self.pointerY = pointerY;
53088
53089        if (isFixed) {
53090          pointerX -= _getDocScrollLeft$1(ownerDoc);
53091          pointerY -= _getDocScrollTop$1(ownerDoc);
53092        }
53093
53094        if (rotationMode) {
53095          y = Math.atan2(rotationOrigin.y - pointerY, pointerX - rotationOrigin.x) * _RAD2DEG;
53096          dif = self.y - y;
53097
53098          if (dif > 180) {
53099            startElementY -= 360;
53100            self.y = y;
53101          } else if (dif < -180) {
53102            startElementY += 360;
53103            self.y = y;
53104          }
53105
53106          if (self.x !== startElementX || Math.abs(startElementY - y) > minimumMovement) {
53107            self.y = y;
53108            x = startElementX + (startElementY - y) * dragTolerance;
53109          } else {
53110            x = startElementX;
53111          }
53112        } else {
53113          if (matrix) {
53114            temp = pointerX * matrix.a + pointerY * matrix.c + matrix.e;
53115            pointerY = pointerX * matrix.b + pointerY * matrix.d + matrix.f;
53116            pointerX = temp;
53117          }
53118
53119          yChange = pointerY - startPointerY;
53120          xChange = pointerX - startPointerX;
53121
53122          if (yChange < minimumMovement && yChange > -minimumMovement) {
53123            yChange = 0;
53124          }
53125
53126          if (xChange < minimumMovement && xChange > -minimumMovement) {
53127            xChange = 0;
53128          }
53129
53130          if ((self.lockAxis || self.lockedAxis) && (xChange || yChange)) {
53131            temp = self.lockedAxis;
53132
53133            if (!temp) {
53134              self.lockedAxis = temp = allowX && Math.abs(xChange) > Math.abs(yChange) ? "y" : allowY ? "x" : null;
53135
53136              if (temp && _isFunction(self.vars.onLockAxis)) {
53137                self.vars.onLockAxis.call(self, self.pointerEvent);
53138              }
53139            }
53140
53141            if (temp === "y") {
53142              yChange = 0;
53143            } else if (temp === "x") {
53144              xChange = 0;
53145            }
53146          }
53147
53148          x = _round(startElementX + xChange * dragTolerance);
53149          y = _round(startElementY + yChange * dragTolerance);
53150        }
53151
53152        if ((snapX || snapY || snapXY) && (self.x !== x || self.y !== y && !rotationMode)) {
53153          if (snapXY) {
53154            _temp1.x = x;
53155            _temp1.y = y;
53156            temp = snapXY(_temp1);
53157            x = _round(temp.x);
53158            y = _round(temp.y);
53159          }
53160
53161          if (snapX) {
53162            x = _round(snapX(x));
53163          }
53164
53165          if (snapY) {
53166            y = _round(snapY(y));
53167          }
53168        }
53169
53170        if (hasBounds) {
53171          if (x > maxX) {
53172            x = maxX + Math.round((x - maxX) * edgeTolerance);
53173          } else if (x < minX) {
53174            x = minX + Math.round((x - minX) * edgeTolerance);
53175          }
53176
53177          if (!rotationMode) {
53178            if (y > maxY) {
53179              y = Math.round(maxY + (y - maxY) * edgeTolerance);
53180            } else if (y < minY) {
53181              y = Math.round(minY + (y - minY) * edgeTolerance);
53182            }
53183          }
53184        }
53185
53186        if (self.x !== x || self.y !== y && !rotationMode) {
53187          if (rotationMode) {
53188            self.endRotation = self.x = self.endX = x
vendor: 13,666 bytes, lines 53188-53595
53188;
53189            dirty = true;
53190          } else {
53191            if (allowY) {
53192              self.y = self.endY = y;
53193              dirty = true;
53194            }
53195
53196            if (allowX) {
53197              self.x = self.endX = x;
53198              dirty = true;
53199            }
53200          }
53201
53202          if (!invokeOnMove || _dispatchEvent(self, "move", "onMove") !== false) {
53203            if (!self.isDragging && self.isPressed) {
53204              self.isDragging = dragged = true;
53205
53206              _dispatchEvent(self, "dragstart", "onDragStart");
53207            }
53208          } else {
53209            self.pointerX = prevPointerX;
53210            self.pointerY = prevPointerY;
53211            startElementY = prevStartElementY;
53212            self.x = prevX;
53213            self.y = prevY;
53214            self.endX = prevEndX;
53215            self.endY = prevEndY;
53216            self.endRotation = prevEndRotation;
53217            dirty = prevDirty;
53218          }
53219        }
53220      },
53221          onRelease = function onRelease(e, force) {
53222        if (!enabled || !self.isPressed || e && touchID != null && !force && (e.pointerId && e.pointerId !== touchID && e.target !== target || e.changedTouches && !_hasTouchID(e.changedTouches, touchID))) {
53223          isPreventingDefault && e && enabled && _preventDefault(e);
53224          return;
53225        }
53226
53227        self.isPressed = false;
53228        var originalEvent = e,
53229            wasDragging = self.isDragging,
53230            isContextMenuRelease = self.vars.allowContextMenu && e && (e.ctrlKey || e.which > 2),
53231            placeholderDelayedCall = gsap.delayedCall(0.001, removePlaceholder),
53232            touches,
53233            i,
53234            syntheticEvent,
53235            eventTarget,
53236            syntheticClick;
53237
53238        if (touchEventTarget) {
53239          _removeListener(touchEventTarget, "touchend", onRelease);
53240
53241          _removeListener(touchEventTarget, "touchmove", onMove);
53242
53243          _removeListener(touchEventTarget, "touchcancel", onRelease);
53244
53245          _removeListener(ownerDoc, "touchstart", _onMultiTouchDocument);
53246        } else {
53247          _removeListener(ownerDoc, "mousemove", onMove);
53248        }
53249
53250        _removeListener(_win$1, "touchforcechange", _preventDefault);
53251
53252        if (!_supportsPointer || !touchEventTarget) {
53253          _removeListener(ownerDoc, "mouseup", onRelease);
53254
53255          e && e.target && _removeListener(e.target, "mouseup", onRelease);
53256        }
53257
53258        dirty = false;
53259
53260        if (wasDragging) {
53261          dragEndTime = _lastDragTime = _getTime();
53262          self.isDragging = false;
53263        }
53264
53265        _removeFromRenderQueue(render);
53266
53267        if (isClicking && !isContextMenuRelease) {
53268          if (e) {
53269            _removeListener(e.target, "change", onRelease);
53270
53271            self.pointerEvent = originalEvent;
53272          }
53273
53274          _setSelectable(triggers, false);
53275
53276          _dispatchEvent(self, "release", "onRelease");
53277
53278          _dispatchEvent(self, "click", "onClick");
53279
53280          isClicking = false;
53281          return;
53282        }
53283
53284        i = triggers.length;
53285
53286        while (--i > -1) {
53287          _setStyle(triggers[i], "cursor", vars.cursor || (vars.cursor !== false ? _defaultCursor : null));
53288        }
53289
53290        _dragCount--;
53291
53292        if (e) {
53293          touches = e.changedTouches;
53294
53295          if (touches) {
53296            e = touches[0];
53297
53298            if (e !== touch && e.identifier !== touchID) {
53299              i = touches.length;
53300
53301              while (--i > -1 && (e = touches[i]).identifier !== touchID && e.target !== target) {}
53302
53303              if (i < 0 && !force) {
53304                return;
53305              }
53306            }
53307          }
53308
53309          self.pointerEvent = originalEvent;
53310          self.pointerX = e.pageX;
53311          self.pointerY = e.pageY;
53312        }
53313
53314        if (isContextMenuRelease && originalEvent) {
53315          _preventDefault(originalEvent);
53316
53317          isPreventingDefault = true;
53318
53319          _dispatchEvent(self, "release", "onRelease");
53320        } else if (originalEvent && !wasDragging) {
53321          isPreventingDefault = false;
53322
53323          if (interrupted && (vars.snap || vars.bounds)) {
53324            animate(vars.inertia || vars.throwProps);
53325          }
53326
53327          _dispatchEvent(self, "release", "onRelease");
53328
53329          if ((!_isAndroid || originalEvent.type !== "touchmove") && originalEvent.type.indexOf("cancel") === -1) {
53330            _dispatchEvent(self, "click", "onClick");
53331
53332            if (_getTime() - clickTime < 300) {
53333              _dispatchEvent(self, "doubleclick", "onDoubleClick");
53334            }
53335
53336            eventTarget = originalEvent.target || target;
53337            clickTime = _getTime();
53338
53339            syntheticClick = function syntheticClick() {
53340              if (clickTime !== clickDispatch && self.enabled() && !self.isPressed && !originalEvent.defaultPrevented) {
53341                if (eventTarget.click) {
53342                  eventTarget.click();
53343                } else if (ownerDoc.createEvent) {
53344                  syntheticEvent = ownerDoc.createEvent("MouseEvents");
53345                  syntheticEvent.initMouseEvent("click", true, true, _win$1, 1, self.pointerEvent.screenX, self.pointerEvent.screenY, self.pointerX, self.pointerY, false, false, false, false, 0, null);
53346                  eventTarget.dispatchEvent(syntheticEvent);
53347                }
53348              }
53349            };
53350
53351            if (!_isAndroid && !originalEvent.defaultPrevented) {
53352              gsap.delayedCall(0.05, syntheticClick);
53353            }
53354          }
53355        } else {
53356          animate(vars.inertia || vars.throwProps);
53357
53358          if (!self.allowEventDefault && originalEvent && (vars.dragClickables !== false || !isClickable.call(self, originalEvent.target)) && wasDragging && (!allowNativeTouchScrolling || touchDragAxis && allowNativeTouchScrolling === touchDragAxis) && originalEvent.cancelable !== false) {
53359            isPreventingDefault = true;
53360
53361            _preventDefault(originalEvent);
53362          } else {
53363            isPreventingDefault = false;
53364          }
53365
53366          _dispatchEvent(self, "release", "onRelease");
53367        }
53368
53369        isTweening() && placeholderDelayedCall.duration(self.tween.duration());
53370        wasDragging && _dispatchEvent(self, "dragend", "onDragEnd");
53371        return true;
53372      },
53373          updateScroll = function updateScroll(e) {
53374        if (e && self.isDragging && !scrollProxy) {
53375          var parent = e.target || target.parentNode,
53376              deltaX = parent.scrollLeft - parent._gsScrollX,
53377              deltaY = parent.scrollTop - parent._gsScrollY;
53378
53379          if (deltaX || deltaY) {
53380            if (matrix) {
53381              startPointerX -= deltaX * matrix.a + deltaY * matrix.c;
53382              startPointerY -= deltaY * matrix.d + deltaX * matrix.b;
53383            } else {
53384              startPointerX -= deltaX;
53385              startPointerY -= deltaY;
53386            }
53387
53388            parent._gsScrollX += deltaX;
53389            parent._gsScrollY += deltaY;
53390            setPointerPosition(self.pointerX, self.pointerY);
53391          }
53392        }
53393      },
53394          onClick = function onClick(e) {
53395        var time = _getTime(),
53396            recentlyClicked = time - clickTime < 100,
53397            recentlyDragged = time - dragEndTime < 50,
53398            alreadyDispatched = recentlyClicked && clickDispatch === clickTime,
53399            defaultPrevented = self.pointerEvent && self.pointerEvent.defaultPrevented,
53400            alreadyDispatchedTrusted = recentlyClicked && trustedClickDispatch === clickTime,
53401            trusted = e.isTrusted || e.isTrusted == null && recentlyClicked && alreadyDispatched;
53402
53403        if ((alreadyDispatched || recentlyDragged && self.vars.suppressClickOnDrag !== false) && e.stopImmediatePropagation) {
53404          e.stopImmediatePropagation();
53405        }
53406
53407        if (recentlyClicked && !(self.pointerEvent && self.pointerEvent.defaultPrevented) && (!alreadyDispatched || trusted && !alreadyDispatchedTrusted)) {
53408          if (trusted && alreadyDispatched) {
53409            trustedClickDispatch = clickTime;
53410          }
53411
53412          clickDispatch = clickTime;
53413          return;
53414        }
53415
53416        if (self.isPressed || recentlyDragged || recentlyClicked) {
53417          if (!trusted || !e.detail || !recentlyClicked || defaultPrevented) {
53418            _preventDefault(e);
53419          }
53420        }
53421
53422        if (!recentlyClicked && !recentlyDragged && !dragged) {
53423          e && e.target && (self.pointerEvent = e);
53424
53425          _dispatchEvent(self, "click", "onClick");
53426        }
53427      },
53428          localizePoint = function localizePoint(p) {
53429        return matrix ? {
53430          x: p.x * matrix.a + p.y * matrix.c + matrix.e,
53431          y: p.x * matrix.b + p.y * matrix.d + matrix.f
53432        } : {
53433          x: p.x,
53434          y: p.y
53435        };
53436      };
53437
53438      old = Draggable.get(target);
53439      old && old.kill();
53440
53441      _this2.startDrag = function (event, align) {
53442        var r1, r2, p1, p2;
53443        onPress(event || self.pointerEvent, true);
53444
53445        if (align && !self.hitTest(event || self.pointerEvent)) {
53446          r1 = _parseRect(event || self.pointerEvent);
53447          r2 = _parseRect(target);
53448          p1 = localizePoint({
53449            x: r1.left + r1.width / 2,
53450            y: r1.top + r1.height / 2
53451          });
53452          p2 = localizePoint({
53453            x: r2.left + r2.width / 2,
53454            y: r2.top + r2.height / 2
53455          });
53456          startPointerX -= p1.x - p2.x;
53457          startPointerY -= p1.y - p2.y;
53458        }
53459
53460        if (!self.isDragging) {
53461          self.isDragging = dragged = true;
53462
53463          _dispatchEvent(self, "dragstart", "onDragStart");
53464        }
53465      };
53466
53467      _this2.drag = onMove;
53468
53469      _this2.endDrag = function (e) {
53470        return onRelease(e || self.pointerEvent, true);
53471      };
53472
53473      _this2.timeSinceDrag = function () {
53474        return self.isDragging ? 0 : (_getTime() - dragEndTime) / 1000;
53475      };
53476
53477      _this2.timeSinceClick = function () {
53478        return (_getTime() - clickTime) / 1000;
53479      };
53480
53481      _this2.hitTest = function (target, threshold) {
53482        return Draggable.hitTest(self.target, target, threshold);
53483      };
53484
53485      _this2.getDirection = function (from, diagonalThreshold) {
53486        var mode = from === "velocity" && InertiaPlugin ? from : _isObject(from) && !rotationMode ? "element" : "start",
53487            xChange,
53488            yChange,
53489            ratio,
53490            direction,
53491            r1,
53492            r2;
53493
53494        if (mode === "element") {
53495          r1 = _parseRect(self.target);
53496          r2 = _parseRect(from);
53497        }
53498
53499        xChange = mode === "start" ? self.x - startElementX : mode === "velocity" ? InertiaPlugin.getVelocity(target, xProp) : r1.left + r1.width / 2 - (r2.left + r2.width / 2);
53500
53501        if (rotationMode) {
53502          return xChange < 0 ? "counter-clockwise" : "clockwise";
53503        } else {
53504          diagonalThreshold = diagonalThreshold || 2;
53505          yChange = mode === "start" ? self.y - startElementY : mode === "velocity" ? InertiaPlugin.getVelocity(target, yProp) : r1.top + r1.height / 2 - (r2.top + r2.height / 2);
53506          ratio = Math.abs(xChange / yChange);
53507          direction = ratio < 1 / diagonalThreshold ? "" : xChange < 0 ? "left" : "right";
53508
53509          if (ratio < diagonalThreshold) {
53510            if (direction !== "") {
53511              direction += "-";
53512            }
53513
53514            direction += yChange < 0 ? "up" : "down";
53515          }
53516        }
53517
53518        return direction;
53519      };
53520
53521      _this2.applyBounds = function (newBounds, sticky) {
53522        var x, y, forceZeroVelocity, e, parent, isRoot;
53523
53524        if (newBounds && vars.bounds !== newBounds) {
53525          vars.bounds = newBounds;
53526          return self.update(true, sticky);
53527        }
53528
53529        syncXY(true);
53530        calculateBounds();
53531
53532        if (hasBounds && !isTweening()) {
53533          x = self.x;
53534          y = self.y;
53535
53536          if (x > maxX) {
53537            x = maxX;
53538          } else if (x < minX) {
53539            x = minX;
53540          }
53541
53542          if (y > maxY) {
53543            y = maxY;
53544          } else if (y < minY) {
53545            y = minY;
53546          }
53547
53548          if (self.x !== x || self.y !== y) {
53549            forceZeroVelocity = true;
53550            self.x = self.endX = x;
53551
53552            if (rotationMode) {
53553              self.endRotation = x;
53554            } else {
53555              self.y = self.endY = y;
53556            }
53557
53558            dirty = true;
53559            render(true);
53560
53561            if (self.autoScroll && !self.isDragging) {
53562              _recordMaxScrolls(target.parentNode);
53563
53564              e = target;
53565              _windowProxy.scrollTop = _win$1.pageYOffset != null ? _win$1.pageYOffset : ownerDoc.documentElement.scrollTop != null ? ownerDoc.documentElement.scrollTop : ownerDoc.body.scrollTop;
53566              _windowProxy.scrollLeft = _win$1.pageXOffset != null ? _win$1.pageXOffset : ownerDoc.documentElement.scrollLeft != null ? ownerDoc.documentElement.scrollLeft : ownerDoc.body.scrollLeft;
53567
53568              while (e && !isRoot) {
53569                isRoot = _isRoot(e.parentNode);
53570                parent = isRoot ? _windowProxy : e.parentNode;
53571
53572                if (allowY && parent.scrollTop > parent._gsMaxScrollY) {
53573                  parent.scrollTop = parent._gsMaxScrollY;
53574                }
53575
53576                if (allowX && parent.scrollLeft > parent._gsMaxScrollX) {
53577                  parent.scrollLeft = parent._gsMaxScrollX;
53578                }
53579
53580                e = parent;
53581              }
53582            }
53583          }
53584
53585          if (self.isThrowing && (forceZeroVelocity || self.endX > maxX || self.endX < minX || self.endY > maxY || self.endY < minY)) {
53586            animate(vars.inertia || vars.throwProps, forceZeroVelocity);
53587          }
53588        }
53589
53590        return self;
53591      };
53592
53593      _this2.update = function (applyBounds, sticky, ignoreExternalChanges) {
53594        if (sticky && self.isPressed) {
53595          
vendor: 3,070 bytes, lines 53595-53696
53595var m = getGlobalMatrix(target),
53596              p = innerMatrix.apply({
53597            x: self.x - startElementX,
53598            y: self.y - startElementY
53599          }),
53600              m2 = getGlobalMatrix(target.parentNode, true);
53601          m2.apply({
53602            x: m.e - p.x,
53603            y: m.f - p.y
53604          }, p);
53605          self.x -= p.x - m2.e;
53606          self.y -= p.y - m2.f;
53607          render(true);
53608          recordStartPositions();
53609        }
53610
53611        var x = self.x,
53612            y = self.y;
53613        updateMatrix(!sticky);
53614
53615        if (applyBounds) {
53616          self.applyBounds();
53617        } else {
53618          dirty && ignoreExternalChanges && render(true);
53619          syncXY(true);
53620        }
53621
53622        if (sticky) {
53623          setPointerPosition(self.pointerX, self.pointerY);
53624          dirty && render(true);
53625        }
53626
53627        if (self.isPressed && !sticky && (allowX && Math.abs(x - self.x) > 0.01 || allowY && Math.abs(y - self.y) > 0.01 && !rotationMode)) {
53628          recordStartPositions();
53629        }
53630
53631        if (self.autoScroll) {
53632          _recordMaxScrolls(target.parentNode, self.isDragging);
53633
53634          checkAutoScrollBounds = self.isDragging;
53635          render(true);
53636
53637          _removeScrollListener(target, updateScroll);
53638
53639          _addScrollListener(target, updateScroll);
53640        }
53641
53642        return self;
53643      };
53644
53645      _this2.enable = function (type) {
53646        var setVars = {
53647          lazy: true
53648        },
53649            id,
53650            i,
53651            trigger;
53652
53653        if (vars.cursor !== false) {
53654          setVars.cursor = vars.cursor || _defaultCursor;
53655        }
53656
53657        if (gsap.utils.checkPrefix("touchCallout")) {
53658          setVars.touchCallout = "none";
53659        }
53660
53661        if (type !== "soft") {
53662          _setTouchActionForAllDescendants(triggers, allowX === allowY ? "none" : vars.allowNativeTouchScrolling && target.scrollHeight === target.clientHeight === (target.scrollWidth === target.clientHeight) || vars.allowEventDefault ? "manipulation" : allowX ? "pan-y" : "pan-x");
53663
53664          i = triggers.length;
53665
53666          while (--i > -1) {
53667            trigger = triggers[i];
53668            _supportsPointer || _addListener(trigger, "mousedown", onPress);
53669
53670            _addListener(trigger, "touchstart", onPress);
53671
53672            _addListener(trigger, "click", onClick, true);
53673
53674            gsap.set(trigger, setVars);
53675
53676            if (trigger.getBBox && trigger.ownerSVGElement && allowX !== allowY) {
53677              gsap.set(trigger.ownerSVGElement, {
53678                touchAction: vars.allowNativeTouchScrolling || vars.allowEventDefault ? "manipulation" : allowX ? "pan-y" : "pan-x"
53679              });
53680            }
53681
53682            vars.allowContextMenu || _addListener(trigger, "contextmenu", onContextMenu);
53683          }
53684
53685          _setSelectable(triggers, false);
53686        }
53687
53688        _addScrollListener(target, updateScroll);
53689
53690        enabled = true;
53691
53692        if (InertiaPlugin && type !== "soft") {
53693          InertiaPlugin.track(scrollProxy || target, xyMode ? "x,y" : rotationMode ? "rotation" : "top,left");
53694        }
53695
53696        target._gsDragID = id =
vendor: 5,466 bytes, lines 53696-53902
53696 "d" + _lookupCount++;
53697        _lookup[id] = self;
53698
53699        if (scrollProxy) {
53700          scrollProxy.enable();
53701          scrollProxy.element._gsDragID = id;
53702        }
53703
53704        (vars.bounds || rotationMode) && recordStartPositions();
53705        vars.bounds && self.applyBounds();
53706        return self;
53707      };
53708
53709      _this2.disable = function (type) {
53710        var dragging = self.isDragging,
53711            i = triggers.length,
53712            trigger;
53713
53714        while (--i > -1) {
53715          _setStyle(triggers[i], "cursor", null);
53716        }
53717
53718        if (type !== "soft") {
53719          _setTouchActionForAllDescendants(triggers, null);
53720
53721          i = triggers.length;
53722
53723          while (--i > -1) {
53724            trigger = triggers[i];
53725
53726            _setStyle(trigger, "touchCallout", null);
53727
53728            _removeListener(trigger, "mousedown", onPress);
53729
53730            _removeListener(trigger, "touchstart", onPress);
53731
53732            _removeListener(trigger, "click", onClick, true);
53733
53734            _removeListener(trigger, "contextmenu", onContextMenu);
53735          }
53736
53737          _setSelectable(triggers, true);
53738
53739          if (touchEventTarget) {
53740            _removeListener(touchEventTarget, "touchcancel", onRelease);
53741
53742            _removeListener(touchEventTarget, "touchend", onRelease);
53743
53744            _removeListener(touchEventTarget, "touchmove", onMove);
53745          }
53746
53747          _removeListener(ownerDoc, "mouseup", onRelease);
53748
53749          _removeListener(ownerDoc, "mousemove", onMove);
53750        }
53751
53752        _removeScrollListener(target, updateScroll);
53753
53754        enabled = false;
53755
53756        if (InertiaPlugin && type !== "soft") {
53757          InertiaPlugin.untrack(scrollProxy || target, xyMode ? "x,y" : rotationMode ? "rotation" : "top,left");
53758          self.tween && self.tween.kill();
53759        }
53760
53761        scrollProxy && scrollProxy.disable();
53762
53763        _removeFromRenderQueue(render);
53764
53765        self.isDragging = self.isPressed = isClicking = false;
53766        dragging && _dispatchEvent(self, "dragend", "onDragEnd");
53767        return self;
53768      };
53769
53770      _this2.enabled = function (value, type) {
53771        return arguments.length ? value ? self.enable(type) : self.disable(type) : enabled;
53772      };
53773
53774      _this2.kill = function () {
53775        self.isThrowing = false;
53776        self.tween && self.tween.kill();
53777        self.disable();
53778        gsap.set(triggers, {
53779          clearProps: "userSelect"
53780        });
53781        delete _lookup[target._gsDragID];
53782        return self;
53783      };
53784
53785      _this2.revert = function () {
53786        this.kill();
53787        this.styles && this.styles.revert();
53788      };
53789
53790      if (~type.indexOf("scroll")) {
53791        scrollProxy = _this2.scrollProxy = new ScrollProxy(target, _extend({
53792          onKill: function onKill() {
53793            self.isPressed && onRelease(null);
53794          }
53795        }, vars));
53796        target.style.overflowY = allowY && !_isTouchDevice ? "auto" : "hidden";
53797        target.style.overflowX = allowX && !_isTouchDevice ? "auto" : "hidden";
53798        target = scrollProxy.content;
53799      }
53800
53801      if (rotationMode) {
53802        killProps.rotation = 1;
53803      } else {
53804        if (allowX) {
53805          killProps[xProp] = 1;
53806        }
53807
53808        if (allowY) {
53809          killProps[yProp] = 1;
53810        }
53811      }
53812
53813      gsCache.force3D = "force3D" in vars ? vars.force3D : true;
53814
53815      _context(_assertThisInitialized(_this2));
53816
53817      _this2.enable();
53818
53819      return _this2;
53820    }
53821
53822    Draggable.register = function register(core) {
53823      gsap = core;
53824
53825      _initCore();
53826    };
53827
53828    Draggable.create = function create(targets, vars) {
53829      _coreInitted || _initCore(true);
53830      return _toArray(targets).map(function (target) {
53831        return new Draggable(target, vars);
53832      });
53833    };
53834
53835    Draggable.get = function get(target) {
53836      return _lookup[(_toArray(target)[0] || {})._gsDragID];
53837    };
53838
53839    Draggable.timeSinceDrag = function timeSinceDrag() {
53840      return (_getTime() - _lastDragTime) / 1000;
53841    };
53842
53843    Draggable.hitTest = function hitTest(obj1, obj2, threshold) {
53844      if (obj1 === obj2) {
53845        return false;
53846      }
53847
53848      var r1 = _parseRect(obj1),
53849          r2 = _parseRect(obj2),
53850          top = r1.top,
53851          left = r1.left,
53852          right = r1.right,
53853          bottom = r1.bottom,
53854          width = r1.width,
53855          height = r1.height,
53856          isOutside = r2.left > right || r2.right < left || r2.top > bottom || r2.bottom < top,
53857          overlap,
53858          area,
53859          isRatio;
53860
53861      if (isOutside || !threshold) {
53862        return !isOutside;
53863      }
53864
53865      isRatio = (threshold + "").indexOf("%") !== -1;
53866      threshold = parseFloat(threshold) || 0;
53867      overlap = {
53868        left: Math.max(left, r2.left),
53869        top: Math.max(top, r2.top)
53870      };
53871      overlap.width = Math.min(right, r2.right) - overlap.left;
53872      overlap.height = Math.min(bottom, r2.bottom) - overlap.top;
53873
53874      if (overlap.width < 0 || overlap.height < 0) {
53875        return false;
53876      }
53877
53878      if (isRatio) {
53879        threshold *= 0.01;
53880        area = overlap.width * overlap.height;
53881        return area >= width * height * threshold || area >= r2.width * r2.height * threshold;
53882      }
53883
53884      return overlap.width > threshold && overlap.height > threshold;
53885    };
53886
53887    return Draggable;
53888  }(EventDispatcher);
53889
53890  _setDefaults(Draggable.prototype, {
53891    pointerX: 0,
53892    pointerY: 0,
53893    startX: 0,
53894    startY: 0,
53895    deltaX: 0,
53896    deltaY: 0,
53897    isDragging: false,
53898    isPressed: false
53899  });
53900
53901  Draggable.zIndex = 1000;
53902  Draggable.version = "3.1
539022.5";
53903  _getGSAP() && gsap.registerPlugin(Draggable);
53904
53905  exports.Draggable = Draggable;
53906  exports.default = Draggable;
53907
53908  if (typeof(window) === 'undefined' || window !== exports) {Object.defineProperty(exports, '__esModule', { value: true });} else {delete window.default;}
53909
53910})));
53911/* ========================================================================
53912 * Bootstrap: collapse.js v3.1.1
53913 * http://getbootstrap.com/javascript/#collapse
53914 * ========================================================================
53915 * Copyright 2011-2014 Twitter, Inc.
53916 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
53917 * ======================================================================== */
53918
53919
53920+function ($) {
53921	'use strict';
53922
53923	// COLLAPSE PUBLIC CLASS DEFINITION
53924	// ================================
53925
53926	var Collapse = function (element, options) {
53927		this.$element      = $(element)
53928		this.options       = $.extend({}, Collapse.DEFAULTS, options)
53929		this.transitioning = null
53930
53931		if (this.options.parent) this.$parent = $(this.options.parent)
53932		if (this.options.toggle) this.toggle()
53933	}
53934
53935	Collapse.DEFAULTS = {
53936		toggle: true
53937	}
53938
53939	Collapse.prototype.dimension = function () {
53940		var hasWidth = this.$element.hasClass('width')
53941		return hasWidth ? 'width' : 'height'
53942	}
53943
53944	Collapse.prototype.show = function () {
53945		if (this.transitioning || this.$element.hasClass('in')) return
53946
53947		var startEvent = $.Event('show.bs.collapse')
53948		this.$element.trigger(startEvent)
53949		if (startEvent.isDefaultPrevented()) return
53950
53951		var actives = this.$parent && this.$parent.find('> .panel > .in')
53952
53953		if (actives && actives.length) {
53954			var hasData = actives.data('bs.collapse')
53955			if (hasData && hasData.transitioning) return
53956			//START UNCODE EDIT
53957			var parentNoToggle = this.$parent.data('no-toggle')
53958			if (!parentNoToggle) {
53959				actives.collapse('hide')
53960			}
53961			//END UNCODE EDIT
53962			hasData || actives.data('bs.collapse', null)
53963		}
53964
53965		var dimension = this.dimension()
53966
53967		this.$element
53968			.removeClass('collapse')
53969			.addClass('collapsing')[dimension](0)
53970
53971		this.transitioning = 1
53972
53973		var complete = function (e) {
53974			if (e && e.target != this.$element[0]) return
53975			this.$element
53976				.removeClass('collapsing')
53977				.addClass('collapse in')[dimension]('auto')
53978			this.transitioning = 0
53979			this.$element.trigger('shown.bs.collapse')
53980		}
53981
53982		if (!$.support.transition) return complete.call(this)
53983
53984		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
53985
53986		this.$element
53987			.one($.support.transition.end, $.proxy(complete, this))
53988			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
53989	}
53990
53991	Collapse.prototype.hide = function () {
53992		if (this.transitioning || !this.$element.hasClass('in')) return
53993
53994		var startEvent = $.Event('hide.bs.collapse')
53995		this.$element.trigger(startEvent)
53996		if (startEvent.isDefaultPrevented()) return
53997
53998		var dimension = this.dimension()
53999
54000		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
54001
54002		this.$element
54003			.addClass('collapsing')
54004			.removeClass('collapse')
54005			.removeClass('in')
54006
54007		this.transitioning = 1
54008
54009		var complete = function (e) {
54010			if (e && e.target != this.$element[0]) return
54011			this.transitioning = 0
54012			this.$element
54013				.trigger('hidden.bs.collapse')
54014				.removeClass('collapsing')
54015				.addClass('collapse')
54016		}
54017
54018		if (!$.support.transition) return complete.call(this)
54019
54020		this.$element
54021			[dimension](0)
54022			.one($.support.transition.end, $.proxy(complete, this))
54023			.emulateTransitionEnd(350)
54024	}
54025
54026	Collapse.prototype.toggle = function () {
54027		this[this.$element.hasClass('in') ? 'hide' : 'show']()
54028	}
54029
54030
54031	// COLLAPSE PLUGIN DEFINITION
54032	// ==========================
54033
54034	var old = $.fn.collapse
54035
54036	$.fn.collapse = function (option) {
54037		return this.each(function () {
54038			var $this   = $(this)
54039			var data    = $this.data('bs.collapse')
54040			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
54041
54042			if (!data && options.toggle && option == 'show') option = !option
54043			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
54044			if (typeof option == 'string') data[option]()
54045		})
54046	}
54047
54048	$.fn.collapse.Constructor = Collapse
54049
54050
54051	// COLLAPSE NO CONFLICT
54052	// ====================
54053
54054	$.fn.collapse.noConflict = function () {
54055		$.fn.collapse = old
54056		return this
54057	}
54058
54059
54060	// COLLAPSE DATA-API
54061	// =================
54062
54063	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
54064		var $this   = $(this), href
54065		var target  = $this.attr('data-target')
54066				|| e.preventDefault()
54067				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
54068		//Edited by Uncode to replace ID in panel [START]
54069		var _target = href.replace(/^#/, "");
54070		if ( $('[data-id="' + _target + '"]').length ) {
54071			var $target = $('[data-id="' + _target + '"]')
54072		} else {
54073			var $target = $(target)
54074		}
54075		//Edited by Uncode to replace ID in panel [END]
54076		var data    = $target.data('bs.collapse')
54077		var option  = data ? 'toggle' : $this.data()
54078		var parent  = $this.attr('data-parent')
54079		var $parent = parent && $(parent)
54080
54081		if (!data || !data.transitioning) {
54082			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
54083			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
54084		}
54085
54086		$target.collapse(option)
54087	})
54088
54089}(jQuery);
54090
54091/* ========================================================================
54092 * Bootstrap: tab.js v3.1.1
54093 * http://getbootstrap.com/javascript/#tabs
54094 * ========================================================================
54095 * Copyright 2011-2014 Twitter, Inc.
54096 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
54097 * ======================================================================== */
54098
54099
54100+function ($) {
54101  'use strict';
54102
54103  // TAB CLASS DEFINITION
54104  // ====================
54105
54106  var Tab = function (element) {
54107    this.element = $(element)
54108  }
54109
54110  Tab.prototype.show = function () {
54111    var $this    = this.element
54112    var $ul      = $this.closest('ul:not(.dropdown-menu)')
54113    var selector = $this.data('target')
54114
54115    if (!selector) {
54116      selector = $this.attr('href')
54117      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
54118    }
54119
54120    if ($this.parent('li').hasClass('active')) return
54121
54122    var previous = $ul.find('.active:last a')[0]
54123    var e        = $.Event('show.bs.tab', {
54124      relatedTarget: previous
54125    })
54126
54127    $this.trigger(e)
54128
54129    if (e.isDefaultPrevented()) return
54130
54131    //Edited by Uncode to replace ID in panel [START]
54132    var _target = selector.replace(/^#/, "");
54133    if ( $('[data-id="' + _target + '"]').length )
54134      var $target = $('[data-id="' + _target + '"]')
54135    else
54136      var $target = $(selector)
54137    //Edited by Uncode to replace ID in panel [END]
54138
54139    this.activate($this.parent('li'), $ul)
54140    this.activate($target, $target.parent(), function () {
54141      $this.trigger({
54142        type: 'shown.bs.tab',
54143        relatedTarget: previous
54144      })
54145    })
54146  }
54147
54148  Tab.prototype.activate = function (element, container, callback) {
54149    var $active    = container.find('> .active').add(container.find('> .active > .active'))
54150    var transition = callback
54151      && $.support.transition
54152      && $active.hasClass('fade')
54153
54154    function next() {
54155      $active
54156        .removeClass('active')
54157        .find('> .dropdown-menu > .active')
54158        .removeClass('active')
54159
54160      $active
54161        .find('.tab-excerpt').slideUp();
54162
54163      element.addClass('active')
54164      $('.tab-excerpt', element).slideDown();
54165
54166      //if (transition) {
54167        element[0].offsetWidth // reflow for transition
54168        element.add($active).addClass('in')
54169      /*} else {
54170        element.removeClass('fade')
54171      }*/
54172
54173      if (element.parents('.dropdown-menu').length) {
54174        element.closest('li.dropdown').addClass('active')
54175      }
54176
54177      if ( ! element.is('li') ) {
54178        element.closest('.tab-content').find('> .active').not(element).removeClass('active');
54179      }
54180
54181      callback && callback()
54182    }
54183
54184    transition ? 
54185      $active
54186        .one($.support.transition.end, next)
54187        .emulateTransitionEnd(150) :
54188      next()
54189
54190    $active.removeClass('in')
54191  }
54192
54193
54194  // TAB PLUGIN DEFINITION
54195  // =====================
54196
54197  var old = $.fn.tab
54198
54199  $.fn.tab = function ( option ) {
54200    return this.each(function () {
54201      var $this = $(this)
54202      var data  = $this.data('bs.tab')
54203
54204      if (!data) $this.data('bs.tab', (data = new Tab(this)))
54205      if (typeof option == 'string') data[option]()
54206    })
54207  }
54208
54209  $.fn.tab.Constructor = Tab
54210
54211
54212  // TAB NO CONFLICT
54213  // ===============
54214
54215  $.fn.tab.noConflict = function () {
54216    $.fn.tab = old
54217    return this
54218  }
54219
54220
54221  // TAB DATA-API
54222  // ============
54223
54224  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
54225    e.preventDefault()
54226    $(this).tab('show')
54227  })
54228
54229}(jQuery);
54230
54231/* ========================================================================
54232 * Bootstrap: tooltip.js v3.1.1
54233 * http://getbootstrap.com/javascript/#tooltip
54234 * Inspired by the original jQuery.tipsy by Jason Frame
54235 * ========================================================================
54236 * Copyright 2011-2014 Twitter, Inc.
54237 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
54238 * ======================================================================== */
54239
54240
54241+function ($) {
54242  'use strict';
54243
54244  // TOOLTIP PUBLIC CLASS DEFINITION
54245  // ===============================
54246
54247  var Tooltip = function (element, options) {
54248    this.type       =
54249    this.options    =
54250    this.enabled    =
54251    this.timeout    =
54252    this.hoverState =
54253    this.$element   = null
54254
54255    this.init('tooltip', element, options)
54256  }
54257
54258  Tooltip.DEFAULTS = {
54259    animation: true,
54260    placement: 'top',
54261    selector: false,
54262    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
54263    trigger: 'hover focus',
54264    title: '',
54265    delay: 0,
54266    html: false,
54267    container: false,
54268    viewport: {
54269      selector: 'body',
54270      padding: 0
54271    }
54272  }
54273
54274  Tooltip.prototype.init = function (type, element, options) {
54275    this.enabled   = true
54276    this.type      = type
54277    this.$element  = $(element)
54278    this.options   = this.getOptions(options)
54279    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
54280
54281    var triggers = this.options.trigger.split(' ')
54282
54283    for (var i = triggers.length; i--;) {
54284      var trigger = triggers[i]
54285
54286      if (trigger == 'click') {
54287        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
54288      } else if (trigger != 'manual') {
54289        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
54290        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
54291
54292        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
54293        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
54294      }
54295    }
54296
54297    this.options.selector ?
54298      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
54299      this.fixTitle()
54300  }
54301
54302  Tooltip.prototype.getDefaults = function () {
54303    return Tooltip.DEFAULTS
54304  }
54305
54306  Tooltip.prototype.getOptions = function (options) {
54307    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
54308
54309    if (options.delay && typeof options.delay == 'number') {
54310      options.delay = {
54311        show: options.delay,
54312        hide: options.delay
54313      }
54314    }
54315
54316    return options
54317  }
54318
54319  Tooltip.prototype.getDelegateOptions = function () {
54320    var options  = {}
54321    var defaults = this.getDefaults()
54322
54323    this._options && $.each(this._options, function (key, value) {
54324      if (defaults[key] != value) options[key] = value
54325    })
54326
54327    return options
54328  }
54329
54330  Tooltip.prototype.enter = function (obj) {
54331    var self = obj instanceof this.constructor ?
54332      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
54333
54334    clearTimeout(self.timeout)
54335
54336    self.hoverState = 'in'
54337
54338    if (!self.options.delay || !self.options.delay.show) return self.show()
54339
54340    self.timeout = setTimeout(function () {
54341      if (self.hoverState == 'in') self.show()
54342    }, self.options.delay.show)
54343  }
54344
54345  Tooltip.prototype.leave = function (obj) {
54346    var self = obj instanceof this.constructor ?
54347      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
54348
54349    clearTimeout(self.timeout)
54350
54351    self.hoverState = 'out'
54352
54353    if (!self.options.delay || !self.options.delay.hide) return self.hide()
54354
54355    self.timeout = setTimeout(function () {
54356      if (self.hoverState == 'out') self.hide()
54357    }, self.options.delay.hide)
54358  }
54359
54360  Tooltip.prototype.show = function () {
54361    var e = $.Event('show.bs.' + this.type)
54362
54363    if (this.hasContent() && this.enabled) {
54364      this.$element.trigger(e)
54365
54366      if (e.isDefaultPrevented()) return
54367      var that = this;
54368
54369      var $tip = this.tip()
54370
54371      this.setContent()
54372
54373      if (this.options.animation) $tip.addClass('fade')
54374
54375      var placement = typeof this.options.placement == 'function' ?
54376        this.options.placement.call(this, $tip[0], this.$element[0]) :
54377        this.options.placement
54378
54379      var autoToken = /\s?auto?\s?/i
54380      var autoPlace = autoToken.test(placement)
54381      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
54382
54383      $tip
54384        .detach()
54385        .css({ top: 0, left: 0, display: 'block' })
54386        .addClass(placement)
54387
54388      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
54389
54390      var pos          = this.getPosition()
54391      var actualWidth  = $tip[0].offsetWidth
54392      var actualHeight = $tip[0].offsetHeight
54393
54394      if (autoPlace) {
54395        var orgPlacement = placement
54396        var $parent      = this.$element.parent()
54397        var parentDim    = this.getPosition($parent)
54398
54399        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
54400                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
54401                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
54402                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
54403                    placement
54404
54405        $tip
54406          .removeClass(orgPlacement)
54407          .addClass(placement)
54408      }
54409
54410      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
54411
54412      this.applyPlacement(calculatedOffset, placement)
54413      this.hoverState = null
54414
54415      var complete = function() {
54416        that.$element.trigger('shown.bs.' + that.type)
54417      }
54418
54419      $.support.transition && this.$tip.hasClass('fade') ?
54420        $tip
54421          .one($.support.transition.end, complete)
54422          .emulateTransitionEnd(150) :
54423        complete()
54424    }
54425  }
54426
54427  Tooltip.prototype.applyPlacement = function (offset, placement) {
54428    var $tip   = this.tip()
54429    var width  = $tip[0].offsetWidth
54430    var height = $tip[0].offsetHeight
54431
54432    // manually read margins because getBoundingClientRect includes difference
54433    var marginTop = parseInt($tip.css('margin-top'), 10)
54434    var marginLeft = parseInt($tip.css('margin-left'), 10)
54435
54436    // we must check for NaN for ie 8/9
54437    if (isNaN(marginTop))  marginTop  = 0
54438    if (isNaN(marginLeft)) marginLeft = 0
54439
54440    offset.top  = offset.top  + marginTop
54441    offset.left = offset.left + marginLeft
54442
54443    // $.fn.offset doesn't round pixel values
54444    // so we use setOffset directly with our own function B-0
54445    $.offset.setOffset($tip[0], $.extend({
54446      using: function (props) {
54447        $tip.css({
54448          top: Math.round(props.top),
54449          left: Math.round(props.left)
54450        })
54451      }
54452    }, offset), 0)
54453
54454    $tip.addClass('in')
54455
54456    // check to see if placing tip in new offset caused the tip to resize itself
54457    var actualWidth  = $tip[0].offsetWidth
54458    var actualHeight = $tip[0].offsetHeight
54459
54460    if (placement == 'top' && actualHeight != height) {
54461      offset.top = offset.top + height - actualHeight
54462    }
54463
54464    var delta = this.getViewportAdjustedDelta(placement, offset, actualWid
54464th, actualHeight)
54465
54466    if (delta.left) offset.left += delta.left
54467    else offset.top += delta.top
54468
54469    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
54470    var arrowPosition       = delta.left ? 'left'        : 'top'
54471    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
54472
54473    $tip.offset(offset)
54474    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
54475  }
54476
54477  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
54478    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
54479  }
54480
54481  Tooltip.prototype.setContent = function () {
54482    var $tip  = this.tip()
54483    var title = this.getTitle()
54484
54485    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
54486    $tip.removeClass('fade in top bottom left right')
54487  }
54488
54489  Tooltip.prototype.hide = function () {
54490    var that = this
54491    var $tip = this.tip()
54492    var e    = $.Event('hide.bs.' + this.type)
54493
54494    function complete() {
54495      if (that.hoverState != 'in') $tip.detach()
54496      that.$element.trigger('hidden.bs.' + that.type)
54497    }
54498
54499    this.$element.trigger(e)
54500
54501    if (e.isDefaultPrevented()) return
54502
54503    $tip.removeClass('in')
54504
54505    $.support.transition && this.$tip.hasClass('fade') ?
54506      $tip
54507        .one($.support.transition.end, complete)
54508        .emulateTransitionEnd(150) :
54509      complete()
54510
54511    this.hoverState = null
54512
54513    return this
54514  }
54515
54516  Tooltip.prototype.fixTitle = function () {
54517    var $e = this.$element
54518    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
54519      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
54520    }
54521  }
54522
54523  Tooltip.prototype.hasContent = function () {
54524    return this.getTitle()
54525  }
54526
54527  Tooltip.prototype.getPosition = function ($element) {
54528    $element   = $element || this.$element
54529    var el     = $element[0]
54530    var isBody = el.tagName == 'BODY'
54531    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
54532      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
54533      width:  isBody ? $(window).width()  : $element.outerWidth(),
54534      height: isBody ? $(window).height() : $element.outerHeight()
54535    }, isBody ? {top: 0, left: 0} : $element.offset())
54536  }
54537
54538  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
54539    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
54540           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
54541           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
54542        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
54543
54544  }
54545
54546  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
54547    var delta = { top: 0, left: 0 }
54548    if (!this.$viewport) return delta
54549
54550    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
54551    var viewportDimensions = this.getPosition(this.$viewport)
54552
54553    if (/right|left/.test(placement)) {
54554      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
54555      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
54556      if (topEdgeOffset < viewportDimensions.top) { // top overflow
54557        delta.top = viewportDimensions.top - topEdgeOffset
54558      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
54559        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
54559EdgeOffset
54560      }
54561    } else {
54562      var leftEdgeOffset  = pos.left - viewportPadding
54563      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
54564      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
54565        delta.left = viewportDimensions.left - leftEdgeOffset
54566      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
54567        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
54568      }
54569    }
54570
54571    return delta
54572  }
54573
54574  Tooltip.prototype.getTitle = function () {
54575    var title
54576    var $e = this.$element
54577    var o  = this.options
54578
54579    title = $e.attr('data-original-title')
54580      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
54581
54582    return title
54583  }
54584
54585  Tooltip.prototype.tip = function () {
54586    return this.$tip = this.$tip || $(this.options.template)
54587  }
54588
54589  Tooltip.prototype.arrow = function () {
54590    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
54591  }
54592
54593  Tooltip.prototype.validate = function () {
54594    if (!this.$element[0].parentNode) {
54595      this.hide()
54596      this.$element = null
54597      this.options  = null
54598    }
54599  }
54600
54601  Tooltip.prototype.enable = function () {
54602    this.enabled = true
54603  }
54604
54605  Tooltip.prototype.disable = function () {
54606    this.enabled = false
54607  }
54608
54609  Tooltip.prototype.toggleEnabled = function () {
54610    this.enabled = !this.enabled
54611  }
54612
54613  Tooltip.prototype.toggle = function (e) {
54614    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
54615    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
54616  }
54617
54618  Tooltip.prototype.destroy = function () {
54619    clearTimeout(this.timeout)
54620    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
54621  }
54622
54623
54624  // TOOLTIP PLUGIN DEFINITION
54625  // =========================
54626
54627  var old = $.fn.tooltip
54628
54629  $.fn.tooltip = function (option) {
54630    return this.each(function () {
54631      var $this   = $(this)
54632      var data    = $this.data('bs.tooltip')
54633      var options = typeof option == 'object' && option
54634
54635      if (!data && option == 'destroy') return
54636      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
54637      if (typeof option == 'string') data[option]()
54638    })
54639  }
54640
54641  $.fn.tooltip.Constructor = Tooltip
54642
54643
54644  // TOOLTIP NO CONFLICT
54645  // ===================
54646
54647  $.fn.tooltip.noConflict = function () {
54648    $.fn.tooltip = old
54649    return this
54650  }
54651
54652}(jQuery);
54653
54654/* ========================================================================
54655 * Bootstrap: transition.js v3.1.1
54656 * http://getbootstrap.com/javascript/#transitions
54657 * ========================================================================
54658 * Copyright 2011-2014 Twitter, Inc.
54659 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
54660 * ======================================================================== */
54661
54662
54663+function ($) {
54664  'use strict';
54665
54666  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
54667  // ============================================================
54668
54669  function transitionEnd() {
54670    var el = document.createElement('bootstrap')
54671
54672    var transEndEventNames = {
54673      WebkitTransition : 'webkitTransitionEnd',
54674      MozTransition    : 'transitionend',
54675      OTransition      : 'oTransitionEnd otransitionend',
54676      transition       : 'transitionend'
54677    }
54678
54679    for (var name in transEndEventNames) {
54680      if (el.style[name] !== undefined) {
54681        return { end: transEndEventNames[name] }
54682      }
54683    }
54684
54685    return false // explicit for ie8 (  ._.)
54686  }
54687
54688  // http://blog.alexmaccaw.com/css-transitions
54689  $.fn.emulateTransitionEnd = function (duration) {
54690    var called = false, $el = this
54691    $(this).one($.support.transition.end, function () { called = true })
54692    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
54693    setTimeout(callback, duration)
54694    return this
54695  }
54696
54697  $(function () {
54698    $.support.transition = transitionEnd()
54699  })
54700
54701}(jQuery);
54702
54703
54704// ------------------------------------------
54705// Rellax.js
54706// Buttery smooth parallax library
54707// Copyright (c) 2016 Moe Amaya (@moeamaya)
54708// MIT license
54709//
54710// Thanks to Paraxify.js and Jaime Cabllero
54711// for parallax concepts
54712// ------------------------------------------
54713
54714(function (root, factory) {
54715	if (typeof define === 'function' && define.amd) {
54716		// AMD. Register as an anonymous module.
54717		define([], factory);
54718	} else if (typeof module === 'object' && module.exports) {
54719		// Node. Does not work with strict CommonJS, but
54720		// only CommonJS-like environments that support module.exports,
54721		// like Node.
54722		module.exports = factory();
54723	} else {
54724		// Browser globals (root is window)
54725		root.Rellax = factory();
54726	}
54727}(typeof window !== "undefined" ? window : global, function () {
54728	var Rellax = function(el, options){
54729		"use strict";
54730
54731		var self = Object.create(Rellax.prototype);
54732
54733		var posY = 0;
54734		var screenY = 0;
54735		var posX = 0;
54736		var screenX = 0;
54737		var blocks = [];
54738		var pause = true;
54739
54740		// check what requestAnimationFrame to use, and if
54741		// it's not supported, use the onscroll event
54742		var loop = window.requestAnimationFrame ||
54743			window.webkitRequestAnimationFrame ||
54744			window.mozRequestAnimationFrame ||
54745			window.msRequestAnimationFrame ||
54746			window.oRequestAnimationFrame ||
54747			function(callback){ return setTimeout(callback, 1000 / 60); };
54748
54749		// store the id for later use
54750		var loopId = null;
54751
54752		// Test via a getter in the options object to see if the passive property is accessed
54753		var supportsPassive = false;
vendor: 10,724 bytes, lines 54754-55055
54754		try {
54755			var opts = Object.defineProperty({}, 'passive', {
54756				get: function() {
54757					supportsPassive = true;
54758				}
54759			});
54760			window.addEventListener("testPassive", null, opts);
54761			window.removeEventListener("testPassive", null, opts);
54762		} catch (e) {}
54763
54764		// check what cancelAnimation method to use
54765		var clearLoop = window.cancelAnimationFrame || window.mozCancelAnimationFrame || clearTimeout;
54766
54767		// check which transform property to use
54768		var transformProp = window.transformProp || (function(){
54769				var testEl = document.createElement('div');
54770				if (testEl.style.transform === null) {
54771					var vendors = ['Webkit', 'Moz', 'ms'];
54772					for (var vendor in vendors) {
54773						if (testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) {
54774							return vendors[vendor] + 'Transform';
54775						}
54776					}
54777				}
54778				return 'transform';
54779			})();
54780
54781		// Default Settings
54782		self.options = {
54783			speed: -2,
54784			verticalSpeed: null,
54785			horizontalSpeed: null,
54786			breakpoints: [576, 768, 1201],
54787			center: false,
54788			wrapper: null,
54789			relativeToWrapper: false,
54790			round: true,
54791			vertical: true,
54792			horizontal: false,
54793			verticalScrollAxis: "y",
54794			horizontalScrollAxis: "x",
54795			callback: function() {},
54796		};
54797
54798		// User defined options (might have more in the future)
54799		if (options){
54800			Object.keys(options).forEach(function(key){
54801				self.options[key] = options[key];
54802			});
54803		}
54804
54805		function validateCustomBreakpoints () {
54806			if (self.options.breakpoints.length === 3 && Array.isArray(self.options.breakpoints)) {
54807				var isAscending = true;
54808				var isNumerical = true;
54809				var lastVal;
54810				self.options.breakpoints.forEach(function (i) {
54811					if (typeof i !== 'number') isNumerical = false;
54812					if (lastVal !== null) {
54813						if (i < lastVal) isAscending = false;
54814					}
54815					lastVal = i;
54816				});
54817				if (isAscending && isNumerical) return;
54818			}
54819			// revert defaults if set incorrectly
54820			self.options.breakpoints = [576, 768, 1201];
54821			console.warn("Rellax: You must pass an array of 3 numbers in ascending order to the breakpoints option. Defaults reverted");
54822		}
54823
54824		if (options && options.breakpoints) {
54825			validateCustomBreakpoints();
54826		}
54827
54828		// By default, rellax class
54829		if (!el) {
54830			el = '.rellax';
54831		}
54832
54833		// check if el is a className or a node
54834		var elements = typeof el === 'string' ? document.querySelectorAll(el) : [el];
54835
54836		// Now query selector
54837		if (elements.length > 0) {
54838			self.elems = elements;
54839		}
54840
54841		// The elements don't exist
54842		else {
54843			console.warn("Rellax: The elements you're trying to select don't exist.");
54844			return;
54845		}
54846
54847		// Has a wrapper and it exists
54848		if (self.options.wrapper) {
54849			if (!self.options.wrapper.nodeType) {
54850				var wrapper = document.querySelector(self.options.wrapper);
54851
54852				if (wrapper) {
54853					self.options.wrapper = wrapper;
54854				} else {
54855					console.warn("Rellax: The wrapper you're trying to use doesn't exist.");
54856					return;
54857				}
54858			}
54859		}
54860
54861		// set a placeholder for the current breakpoint
54862		var currentBreakpoint;
54863
54864		// helper to determine current breakpoint
54865		var getCurrentBreakpoint = function (w) {
54866			var bp = self.options.breakpoints;
54867			if (w < bp[0]) return 'xs';
54868			if (w >= bp[0] && w < bp[1]) return 'sm';
54869			if (w >= bp[1] && w < bp[2]) return 'md';
54870			return 'lg';
54871		};
54872
54873		// Get and cache initial position of all elements
54874		var cacheBlocks = function() {
54875			for (var i = 0; i < self.elems.length; i++){
54876				var block = createBlock(self.elems[i]);
54877				blocks.push(block);
54878			}
54879		};
54880
54881
54882		// Let's kick this script off
54883		// Build array for cached element values
54884		var init = function() {
54885			for (var i = 0; i < blocks.length; i++){
54886				self.elems[i].style.cssText = blocks[i].style;
54887			}
54888
54889			blocks = [];
54890
54891			screenY = window.innerHeight;
54892			screenX = window.innerWidth;
54893			currentBreakpoint = getCurrentBreakpoint(screenX);
54894
54895			setPosition();
54896
54897			cacheBlocks();
54898
54899			animate();
54900
54901			// If paused, unpause and set listener for window resizing events
54902			if (pause) {
54903				window.addEventListener('resize', init);
54904				pause = false;
54905				// Start the loop
54906				update();
54907			}
54908		};
54909
54910		// We want to cache the parallax blocks'
54911		// values: base, top, height, speed
54912		// el: is dom object, return: el cache values
54913		var createBlock = function(el) {
54914			var dataPercentage = el.getAttribute( 'data-rellax-percentage' );
54915			var dataSpeed = el.getAttribute( 'data-rellax-speed' );
54916			var dataXsSpeed = el.getAttribute( 'data-rellax-xs-speed' );
54917			var dataMobileSpeed = el.getAttribute( 'data-rellax-mobile-speed' );
54918			var dataTabletSpeed = el.getAttribute( 'data-rellax-tablet-speed' );
54919			var dataDesktopSpeed = el.getAttribute( 'data-rellax-desktop-speed' );
54920			var dataVerticalSpeed = el.getAttribute('data-rellax-vertical-speed');
54921			var dataHorizontalSpeed = el.getAttribute('data-rellax-horizontal-speed');
54922			var dataVericalScrollAxis = el.getAttribute('data-rellax-vertical-scroll-axis');
54923			var dataHorizontalScrollAxis = el.getAttribute('data-rellax-horizontal-scroll-axis');
54924			var dataZindex = el.getAttribute( 'data-rellax-zindex' ) || 0;
54925			var dataMin = el.getAttribute( 'data-rellax-min' );
54926			var dataMax = el.getAttribute( 'data-rellax-max' );
54927			var dataMinX = el.getAttribute('data-rellax-min-x');
54928			var dataMaxX = el.getAttribute('data-rellax-max-x');
54929			var dataMinY = el.getAttribute('data-rellax-min-y');
54930			var dataMaxY = el.getAttribute('data-rellax-max-y');
54931			var mapBreakpoints;
54932			var breakpoints = true;
54933
54934			if (!dataXsSpeed && !dataMobileSpeed && !dataTabletSpeed && !dataDesktopSpeed) {
54935				breakpoints = false;
54936			} else {
54937				mapBreakpoints = {
54938					'xs': dataXsSpeed,
54939					'sm': dataMobileSpeed,
54940					'md': dataTabletSpeed,
54941					'lg': dataDesktopSpeed
54942				};
54943			}
54944
54945			// initializing at scrollY = 0 (top of browser), scrollX = 0 (left of browser)
54946			// ensures elements are positioned based on HTML layout.
54947			//
54948			// If the element has the percentage attribute, the posY and posX needs to be
54949			// the current scroll position's value, so that the elements are still positioned based on HTML layout
54950			var wrapperPosY = self.options.wrapper ? self.options.wrapper.scrollTop : (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
54951			// If the option relativeToWrapper is true, use the wrappers offset to top, subtracted from the current page scroll.
54952			if (self.options.relativeToWrapper) {
54953				var scrollPosY = (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
54954				wrapperPosY = scrollPosY - self.options.wrapper.offsetTop;
54955			}
54956			var posY = self.options.vertical ? ( dataPercentage || self.options.center ? wrapperPosY : 0 ) : 0;
54957			var posX = self.options.horizontal ? ( dataPercentage || self.options.center ? self.options.wrapper ? self.options.wrapper.scrollLeft : (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft) : 0 ) : 0;
54958
54959			var blockTop = posY + el.getBoundingClientRect().top;
54960			var blockHeight = el.clientHeight || el.offsetHeight || el.scrollHeight;
54961
54962			var blockLeft = posX + el.getBoundingClientRect().left;
54963			var blockWidth = el.clientWidth || el.offsetWidth || el.scrollWidth;
54964
54965			// apparently parallax equation everyone uses
54966			var percentageY = dataPercentage ? dataPercentage : (posY - blockTop + screenY) / (blockHeight + screenY);
54967			var percentageX = dataPercentage ? dataPercentage : (posX - blockLeft + screenX) / (blockWidth + screenX);
54968			if(self.options.center){ percentageX = 0.5; percentageY = 0.5; }
54969
54970			// Optional individual block speed as data attr, otherwise global speed
54971			var speed = (breakpoints && mapBreakpoints[currentBreakpoint] !== null) ? Number(mapBreakpoints[currentBreakpoint]) : (dataSpeed ? dataSpeed : self.options.speed);
54972			var verticalSpeed = dataVerticalSpeed ? dataVerticalSpeed : self.options.verticalSpeed;
54973			var horizontalSpeed = dataHorizontalSpeed ? dataHorizontalSpeed : self.options.horizontalSpeed;
54974
54975			// Optional individual block movement axis direction as data attr, otherwise global movement direction
54976			var verticalScrollAxis = dataVericalScrollAxis ? dataVericalScrollAxis : self.options.verticalScrollAxis;
54977			var horizontalScrollAxis = dataHorizontalScrollAxis ? dataHorizontalScrollAxis : self.options.horizontalScrollAxis;
54978
54979			var bases = updatePosition(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed);
54980
54981			// ~~Store non-translate3d transforms~~
54982			// Store inline styles and extract transforms
54983			var style = el.style.cssText;
54984			var transform = '';
54985
54986			// Check if there's an inline styled transform
54987			var searchResult = /transform\s*:/i.exec(style);
54988			if (searchResult) {
54989				// Get the index of the transform
54990				var index = searchResult.index;
54991
54992				// Trim the style to the transform point and get the following semi-colon index
54993				var trimmedStyle = style.slice(index);
54994				var delimiter = trimmedStyle.indexOf(';');
54995
54996				// Remove "transform" string and save the attribute
54997				if (delimiter) {
54998					transform = " " + trimmedStyle.slice(11, delimiter).replace(/\s/g,'');
54999				} else {
55000					transform = " " + trimmedStyle.slice(11).replace(/\s/g,'');
55001				}
55002			}
55003
55004			return {
55005				baseX: bases.x,
55006				baseY: bases.y,
55007				top: blockTop,
55008				left: blockLeft,
55009				height: blockHeight,
55010				width: blockWidth,
55011				speed: speed,
55012				verticalSpeed: verticalSpeed,
55013				horizontalSpeed: horizontalSpeed,
55014				verticalScrollAxis: verticalScrollAxis,
55015				horizontalScrollAxis: horizontalScrollAxis,
55016				style: style,
55017				transform: transform,
55018				zindex: dataZindex,
55019				min: dataMin,
55020				max: dataMax,
55021				minX: dataMinX,
55022				maxX: dataMaxX,
55023				minY: dataMinY,
55024				maxY: dataMaxY
55025			};
55026		};
55027
55028		// set scroll position (posY, posX)
55029		// side effect method is not ideal, but okay for now
55030		// returns true if the scroll changed, false if nothing happened
55031		var setPosition = function() {
55032			var oldY = posY;
55033			var oldX = posX;
55034
55035			posY = self.options.wrapper ? self.options.wrapper.scrollTop : (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
55036			posX = self.options.wrapper ? self.options.wrapper.scrollLeft : (document.documentElement || document.body.parentNode || document.body).scrollLeft || window.pageXOffset;
55037			// If option relativeToWrapper is true, use relative wrapper value instead.
55038			if (self.options.relativeToWrapper) {
55039				var scrollPosY = (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
55040				posY = scrollPosY - self.options.wrapper.offsetTop;
55041			}
55042
55043
55044			if (oldY != posY && self.options.vertical) {
55045				// scroll changed, return true
55046				return true;
55047			}
55048
55049			if (oldX != posX && self.options.horizontal) {
55050				// scroll changed, return true
55051				return true;
55052			}
55053
55054			// scroll did not change
55055			return false;
55056		};
55057
55058		// Ahh a pure function, gets new transform value
55059		// based on scrollPosition and speed
55060		// Allow for decimal pixel values
55061		var updatePosition = function(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed) {
55062			var result = {};
55063			var valueX = ((horizontalSpeed ? horizontalSpeed : speed) * (100 * (1 - percentageX)));
55064			var valueY = ((verticalSpeed ? verticalSpeed : speed) * (100 * (1 - percentageY)));
55065
55066			result.x = self.options.round ? Math.round(valueX) : Math.round(valueX * 100) / 100;
55067			result.y = self.options.round ? Math.round(valueY) : Math.round(valueY * 100) / 100;
55068
55069			return result;
55070		};
55071
55072		// Remove event listeners and loop again
55073		var deferredUpdate = function() {
55074			window.removeEventListener('resize', deferredUpdate);
55075			window.removeEventListener('orientationchange', deferredUpdate);
55076			(self.options.wrapper ? self.options.wrapper : window).removeEventListener('scroll', deferredUpdate);
55077			(self.options.wrapper ? self.options.wrapper : document).removeEventListener('touchmove', deferredUpdate);
55078
55079			// loop again
55080			loopId = loop(update);
55081		};
55082
55083		// Loop
55084		var update = function() {
55085			if (setPosition() && pause === false) {
55086				animate();
55087
55088				// loop again
55089				loopId = loop(update);
55090			} else {
55091				loopId = null;
55092
55093				// Don't animate until we get a position updating event
55094				window.addEventListener('resize', deferredUpdate);
55095				window.addEventListener('orientationchange', deferredUpdate);
55096				(self.options.wrapper ? self.options.wrapper : window).addEventListener('scroll', deferredUpdate, supportsPassive ? { passive: true } : false);
55097				(self.options.wrapper ? self.options.wrapper : document).addEventListener('touchmove', deferredUpdate, supportsPassive ? { passive: true } : false);
55098			}
55099		};
55100
55101		// Transform3d on parallax element
55102		var animate = function() {
55103			var positions;
55104			for (var i = 0; i < self.elems.length; i++){
55105				// Determine relevant movement directions
55106				var verticalScrollAxis = blocks[i].verticalScrollAxis.toLowerCase();
55107				var horizontalScrollAxis = blocks[i].horizontalScrollAxis.toLowerCase();
55108				var verticalScrollX = verticalScrollAxis.indexOf("x") != -1 ? posY : 0;
55109				var verticalScrollY = verticalScrollAxis.indexOf("y") != -1 ? posY : 0;
55110				var horizontalScrollX = horizontalScrollAxis.indexOf("x") != -1 ? posX : 0;
55111				var horizontalScrollY = horizontalScrollAxis.indexOf("y") != -1 ? posX : 0;
55112
55113				var percentageY = ((verticalScrollY + horizontalScrollY - blocks[i].top + screenY) / (blocks[i].height + screenY));
55114				var percentageX = ((verticalScrollX + horizontalScrollX - blocks[i].left + screenX) / (blocks[i].width + screenX));
55115
55116				// Subtracting initialize value, so element stays in same spot as HTML
55117				positions = updatePosition(percentageX, percentageY, blocks[i].speed, blocks[i].verticalSpeed, blocks[i].horizontalSpeed);
55118				var positionY = positions.y - blocks[i].baseY;
55119				var positionX = positions.x - blocks[i].baseX;
55120
55121				// The next two "if" blocks go like this:
55122				// Check if a limit is defined (first "min", then "max");
55123				// Check if we need to change the Y or the X
55124				// (Currently working only if just one of the axes is enabled)
55125				// Then, check if the new position is inside the allowed limit
55126				// If so, use new position. If not, set position to limit.
55127
55128				// Check if a min limit is defined
55129				if (blocks[i].min !== null) {
55130					if (self.options.vertical && !self.options.horizontal) {
55131						positionY = positionY <= blocks[i].min ? blocks[i].min : positionY;
55132					}
55133					if (self.options.horizontal && !self.options.vertical) {
55134						positionX = positionX <= blocks[i].min ? blocks[i].min : positionX;
55135					}
55136				}
55137
55138				// Check if directional min limits are defined
55139				if (blocks[i].minY != null) {
55140						positionY = positionY <= blocks[i].minY ? blocks[i].minY : positionY;
55141				}
55142				if (blocks[i].minX != null) {
55143						positionX = positionX <= blocks[i].minX ? blocks[i].minX : positionX;
55144				}
55145
55146				// Check if a max limit is defined
55147				if (blocks[i].max !== null) {
55148					if (self.options.vertical && !self.options.horizontal) {
55149						positionY = positionY >= blocks[i].max ? blocks[i].max : positionY;
55150					}
55151					if (self.options.horizontal && !self.options.vertical) {
55152						positionX = positionX >= blocks[i].max ? blocks[i].max : positionX;
55153					}
55154				}
55155
55156				// Check if directional max limits are defined
55157				if (blocks[i].maxY != null) {
55158						positionY = positionY >= blocks[i].maxY ? blocks[i].maxY : positionY;
55159				}
55160				if (blocks[i].maxX != null) {
55161						positionX = positionX >= blocks[i].maxX ? blocks[i].maxX : positionX;
55162				}
55163
55164				var zindex = blocks[i].zindex;
55165
55166				// Move that element
55167				// (Set the new translation and append initial inline transforms.)
55168				var translate = 'translate3d(' + (self.options.horizontal ? positionX : '0') + 'px,' + (self.options.vertical ? positionY : '0') + 'px,' + zindex + 'px) ' + blocks[i].transform;
55169				self.elems[i].style[transformProp] = translate;
55170			}
55171			self.options.callback(positions);
55172		};
55173
55174		self.destroy = function() {
55175			for (var i = 0; i < self.elems.length; i++){
55176				self.elems[i].style.cssText = blocks[i].style;
55177			}
55178
55179			// Remove resize event listener if not pause, and pause
55180			if (!pause) {
55181				window.removeEventListener('resize', init);
55182				pause = true;
55183			}
55184
55185			// Clear the animation loop to prevent possible memory leak
55186			clearLoop(loopId);
55187			loopId = null;
55188		};
55189
55190		// Init
55191		init();
55192
55193		// Allow to recalculate the initial values whenever we want
55194		self.refresh = init;
55195
55196		return self;
55197	};
55198	return Rellax;
55199}));
55200
55201/*
55202 * OKVideo by OKFocus v2.3.2
55203 * http://okfoc.us
55204 *
55205 * Copyright 2014, OKFocus
55206 * Licensed under the MIT license.
55207 *
55208 */
55209var player, OKEvents, options, videoWidth, videoHeight, YTplayers, youtubePlayers = new Array();
55210// youtube player ready
55211function onYouTubeIframeAPIReady() {
55212	YTplayers = new Array();
55213	jQuery('.uncode-video-container.video').each(function() {
55214		var playerY;
55215		if (jQuery(this).attr('data-provider') == 'youtube') {
55216			var id = jQuery(this).attr('data-id'),
55217				start = jQuery(this).attr('data-start'),
55218				end = jQuery(this).attr('data-end');
55219			start = typeof start && start !== null ? start : 0;
55220			end = typeof end && end !== null ? end : 0;
55221			options = jQuery(window).data('okoptions-' + id);
55222			if ( typeof options === 'undefined' ) {
55223				return true;
55224			}
55225			options.time = jQuery(this).attr('data-t');
55226			playerY = new YT.Player('okplayer-' + id, {
55227				videoId: options.video ? options.video.id : null,
55228				playerVars: {
55229					'autohide': 1,
55230					'autoplay': jQuery(this).hasClass('is-no-control') ? options.autoplay : 0, //options.autoplay,
55231					'disablekb': 1,
55232					'cc_load_policy': options.captions,
55233					'controls': 0,
55234					'enablejsapi': 1,
55235					'fs': 0,
55236					'modestbranding': 1,
55237					'origin': window.location.origin || (window.location.protocol + '//' + window.location.hostname),
55238					'iv_load_policy': options.annotations,
55239					'loop': options.loop,
55240					'showinfo': 0,
55241					'rel': 0,
55242					'wmode': 'opaque',
55243					'hd': options.hd,
55244					'mute': 1,
55245					'start': start,
55246					'end': end
55247				},
55248				events: {
55249					'onReady': OKEvents.yt.ready,
55250					'onStateChange': OKEvents.yt.onStateChange,
55251					'onError': OKEvents.yt.error
55252				}
55253			});
55254			YTplayers[id] = playerY;
55255			playerY.videoId = id;
55256		}
55257
55258	});
55259}
55260// vimeo player ready
55261function vimeoPlayerReady(id) {
55262	options = jQuery(window).data('okoptions-' + id);
55263	if ( typeof options === 'undefined' ) {
55264		return true;
55265	}
55266	var jIframe = options.jobject,
55267		iframe = jIframe[0];
55268
55269	jIframe.attr('src', jIframe.data('src'));
55270	var playerV = new Vimeo.Player(iframe);
55271	// hide player until Vimeo hides controls...
55272	playerV.on('loaded', function(e) {
55273		OKEvents.v.onReady(iframe);
55274		var carouselContainer = jQuery(iframe).closest('.owl-carousel');
55275		if (carouselContainer.length) {
55276			UNCODE.owlPlayVideo(carouselContainer);
55277		}
55278		// "Do not try to add listeners or call functions before receiving this event."
55279		if (OKEvents.utils.isMobile()) {
55280			// mobile devices cannot listen for play event
55281			OKEvents.v.onPlay(playerV);
55282		} else {
55283			playerV.on('play', function(){
55284				OKEvents.v.onPlay(playerV);
55285				jQuery(window).trigger('okevents.v.play', [playerV]);
55286			});
55287			playerV.on('pause', function(){
55288				OKEvents.v.onPause;
55289				jQuery(window).trigger('okevents.v.pause', [playerV]);
55290			});
55291			playerV.on('ended', function(){
55292				OKEvents.v.onFinish
55293				jQuery(window).trigger('okevents.v.ended', [playerV]);
55294			});
55295		}
55296		if (options.time != null) {
55297			var optsTimeStr = (options.time).replace('t=', ''),
55298				timeV = '';
55299
55300			if ( /[a-zA-Z]/g.test(optsTimeStr) ) {
55301				var timeArr = optsTimeStr.split(/([^\d.-])/);
55302				for ( var i = 0; i < timeArr.length; i++ ) {
55303					if ( timeArr[i] === 'h' ) {
55304						timeV += parseFloat(timeArr[i-1]) * 3600;
55305					} else if ( timeArr[i] === 'm' ) {
55306						timeV += parseFloat(timeArr[i-1]) * 60;
55307					} else if ( timeArr[i] === 's' ) {
55308						timeV += parseFloat(timeArr[i-1]);
55309					}
55310				}
55311			} else {
55312				timeV = optsTimeStr;
55313			}
55314
55315			playerV.setCurrentTime(timeV);
55316		}
55317
55318		playerV.setVolume(0);
55319		playerV.play();
55320		jQuery(iframe).css({
55321			visibility: 'visible',
55322			opacity: 1
55323		});
55324		jQuery(iframe).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
55325		jQuery(iframe).closest('#page-header').addClass('video-started');
55326		jQuery(iframe).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
55327
55328		jQuery(window).trigger('okevents.v.loaded', [playerV]);
55329	});
55330}
55331OKEvents = {
55332	yt: {
55333		ready: function(event) {
55334			var id = event.target.videoId,
55335				$video = jQuery('#okplayer-' + id),
55336				options = jQuery(window).data('okoptions-' + id);
55337			if ( typeof options === 'undefined' ) {
55338				return true;
55339			}
55340			youtubePlayers[id] = event.target;
55341			event.target.setVolume(options.volume);
55342			if (options.autoplay === 1) {
55343				if (options.playlist.list) {
55344					player.loadPlaylist(options.playlist.list, options.playlist.index, options.playlist.startSeconds, options.playlist.suggestedQuality);
55345				} else {
55346					var inCarousel = $video.closest('.owl-item');
55347					if (!inCarousel.length || (inCarousel.length && inCarousel.hasClass('active'))) {
55348						if (options.time != null) {
55349							event.target.seekTo(parseInt(options.time));
55350						}
55351						event.target.playVideo();
55352					} else {
55353						event.target.pauseVideo();
55354					}
55355				}
55356			}
55357			OKEvents.utils.isFunction(options.onReady) && options.onReady(event.target);
55358
55359			$video.closest('[data-provider]').on('uncode-resume', function(){
55360				if (options.time != null) {
55361					event.target.seekTo(parseInt(options.time)).playVideo();
55362				} else {
55363					event.target.seekTo(0).playVideo();
55364				}
55365			});
55366
55367			$video.closest('[data-provider]').on('uncode-pause', function(){
55368				if (options.time != null) {
55369					event.target.seekTo(parseInt(options.time)).pauseVideo();
55370				} else {
55371					event.target.seekTo(0).pauseVideo();
55372				}
55373			});
55374			jQuery(window).trigger('okevents.y.loaded', [event]);
55375		},
55376		onStateChange: function(event) {
55377			var id = event.target.videoId,
55378				$video = jQuery('#okplayer-' + id),
55379				options = jQuery(window).data('okoptions-' + id);
55380			if ( typeof options === 'undefined' || typeof event.target.setVolume === 'undefined' ) {
55381				return true;
55382			}
55383			youtubePlayers[id] = event.target;
55384			event.target.setVolume(options.volume);
55385			var $fluid = $video.closest('.fluid-object'),
55386				$tmb = $video.closest('.tmb'),
55387				setTime;
55388			switch (event.data) {
55389				case -1:
55390					OKEvents.utils.isFunction(options.unstarted) && options.unstarted();
55391					break;
55392				case 0:
55393					OKEvents.utils.isFunction(options.onFinished) && options.onFinished();
55394					options.loop && event.target.playVideo();
55395					break;
55396				case 1:
55397					OKEvents.utils.isFunction(options.onPlay) && options.onPlay();
55398					setTimeout(function() {
55399						UNCODE.initVideoComponent(document.body, '.uncode-video-container.video:not(.drop-move), .uncode-video-container.self-video:not(.drop-move)');
55400						jQuery('#okplayer-' + id).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
55401						jQuery('#okplayer-' + id).closest('#page-header').addClass('video-started');
55402						jQuery('#okplayer-' + id).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
55403					}, 300);
55404				break;
55405				case 2:
55406					OKEvents.utils.isFunction(options.onPause) && options.onPause();
55407					break;
55408				case 3:
55409					OKEvents.utils.isFunction(options.buffering) && options.buffering();
55410					break;
55411				case 5:
55412					OKEvents.utils.isFunction(options.cued) && options.cued();
55413					break;
55414				default:
55415					throw "OKVideo: received invalid data from YT player.";
55416			}
55417
55418			jQuery(window).trigger('okevents.y.change', [event]);
55419		},
55420		error: function(event) {
55421			throw event;
55422		}
55423	},
55424	v: {
55425		onReady: function(target) {
55426			if ( typeof options === 'undefined' ) {
55427				return true;
55428			}
55429			OKEvents.utils.isFunction(options.onReady) && options.onReady(target);
55430		},
55431		onPlay: function(player) {
55432			if ( typeof options === 'undefined' ) {
55433				return true;
55434			}
55435			if (!OKEvents.utils.isMobile()) player.setVolume(options.volume);
55436			OKEvents.utils.isFunction(options.onPlay) && options.onPlay();
55437			jQuery(player.element).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
55438			jQuery(player.element).closest('#page-header').addClass('video-started');
55439			jQuery(player.element).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
55440		},
55441		onPause: function() {
55442			if ( typeof options === 'undefined' ) {
55443				return true;
55444			}
55445			OKEvents.utils.isFunction(options.onPause) && options.onPause();
55446		},
55447		onFinish: function() {
55448			if ( typeof options === 'undefined' ) {
55449				return true;
55450			}
55451			OKEvents.utils.isFunction(options.onFinish) && options.onFinish();
55452		}
55453	},
55454	utils: {
55455		isFunction: function(func) {
55456			if (typeof func === 'function') {
55457				return true;
55458			} else {
55459				return false;
55460			}
55461		},
55462		isMobile: function() {
55463			if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/)) {
55464				return true;
55465			} else {
55466				return false;
55467			}
55468		}
55469	}
55470};
55471/**
55472 * vivus - JavaScript library to make drawing animation on SVG
55473 * @version v0.4.4
55474 * @link https://github.com/maxwellito/vivus
55475 * @license MIT
55476 */
55477
55478'use strict';
55479
55480(function () {
55481
55482  'use strict';
55483
55484/**
55485 * Pathformer
55486 * Beta version
55487 *
55488 * Take any SVG version 1.1 and transform
55489 * child elements to 'path' elements
55490 *
55491 * This code is purely forked from
55492 * https://github.com/Waest/SVGPathConverter
55493 */
55494
55495/**
55496 * Class constructor
55497 *
55498 * @param {DOM|String} element Dom element of the SVG or id of it
55499 */
55500function Pathformer(element) {
55501  // Test params
55502  if (typeof element === 'undefined') {
55503	throw new Error('Pathformer [constructor]: "element" parameter is required');
55504  }
55505
55506  // Set the element
55507  if (element.constructor === String) {
55508	element = document.getElementById(element);
55509	if (!element) {
55510	  throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID');
55511	}
55512  }
55513  if (element instanceof window.SVGElement ||
55514	  element instanceof window.SVGGElement ||
55515	  /^svg$/i.test(element.nodeName)) {
55516	this.el = element;
55517  } else {
55518	throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement');
55519  }
55520
55521  // Start
55522  this.scan(element);
55523}
55524
55525/**
55526 * List of tags which can be transformed
55527 * to path elements
55528 *
55529 * @type {Array}
55530 */
55531Pathformer.prototype.TYPES = ['line', 'ellipse', 'circle', 'polygon', 'polyline', 'rect'];
55532
55533/**
55534 * List of attribute names which contain
55535 * data. This array list them to check if
55536 * they contain bad values, like percentage.
55537 *
55538 * @type {Array}
55539 */
55540Pathformer.prototype.ATTR_WATCH = ['cx', 'cy', 'points', 'r', 'rx', 'ry', 'x', 'x1', 'x2', 'y', '
vendor: 24,640 bytes, lines 55540-56338
55540y1', 'y2'];
55541
55542/**
55543 * Finds the elements compatible for transform
55544 * and apply the liked method
55545 *
55546 * @param  {object} options Object from the constructor
55547 */
55548Pathformer.prototype.scan = function (svg) {
55549  var fn, element, pathData, pathDom,
55550	  elements = svg.querySelectorAll(this.TYPES.join(','));
55551
55552  for (var i = 0; i < elements.length; i++) {
55553	element = elements[i];
55554	fn = this[element.tagName.toLowerCase() + 'ToPath'];
55555	pathData = fn(this.parseAttr(element.attributes));
55556	pathDom = this.pathMaker(element, pathData);
55557	element.parentNode.replaceChild(pathDom, element);
55558  }
55559};
55560
55561
55562/**
55563 * Read `line` element to extract and transform
55564 * data, to make it ready for a `path` object.
55565 *
55566 * @param  {DOMelement} element Line element to transform
55567 * @return {object}			 Data for a `path` element
55568 */
55569Pathformer.prototype.lineToPath = function (element) {
55570  var newElement = {},
55571	  x1 = element.x1 || 0,
55572	  y1 = element.y1 || 0,
55573	  x2 = element.x2 || 0,
55574	  y2 = element.y2 || 0;
55575
55576  newElement.d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
55577  return newElement;
55578};
55579
55580/**
55581 * Read `rect` element to extract and transform
55582 * data, to make it ready for a `path` object.
55583 * The radius-border is not taken in charge yet.
55584 * (your help is more than welcomed)
55585 *
55586 * @param  {DOMelement} element Rect element to transform
55587 * @return {object}             Data for a `path` element
55588 */
55589Pathformer.prototype.rectToPath = function (element) {
55590  var newElement = {},
55591      x      = parseFloat(element.x)      || 0,
55592      y      = parseFloat(element.y)      || 0,
55593      width  = parseFloat(element.width)  || 0,
55594      height = parseFloat(element.height) || 0;
55595
55596  if (element.rx || element.ry) {
55597    var rx = parseInt(element.rx, 10) || -1,
55598        ry = parseInt(element.ry, 10) || -1;
55599    rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2);
55600    ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2);
55601
55602    newElement.d = 'M ' + (x + rx) + ',' + y + ' ' +
55603                   'L ' + (x + width - rx) + ',' + y + ' ' +
55604                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' +
55605                   'L ' + (x + width) + ',' + (y + height - ry) + ' ' +
55606                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' +
55607                   'L ' + (x + rx) + ',' + (y + height) + ' ' +
55608                   'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' +
55609                   'L ' + x + ',' + (y + ry) + ' ' +
55610                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y;
55611  }
55612  else {
55613    newElement.d = 'M' + x + ' ' + y + ' ' +
55614                   'L' + (x + width) + ' ' + y + ' ' +
55615                   'L' + (x + width) + ' ' + (y + height) + ' ' +
55616                   'L' + x + ' ' + (y + height) + ' Z';
55617  }
55618  return newElement;
55619};
55620
55621/**
55622 * Read `polyline` element to extract and transform
55623 * data, to make it ready for a `path` object.
55624 *
55625 * @param  {DOMelement} element Polyline element to transform
55626 * @return {object}             Data for a `path` element
55627 */
55628Pathformer.prototype.polylineToPath = function (element) {
55629  var newElement = {},
55630      points = element.points.trim().split(' '),
55631      i, path;
55632
55633  // Reformatting if points are defined without commas
55634  if (element.points.indexOf(',') === -1) {
55635    var formattedPoints = [];
55636    for (i = 0; i < points.length; i+=2) {
55637      formattedPoints.push(points[i] + ',' + points[i+1]);
55638    }
55639    points = formattedPoints;
55640  }
55641
55642  // Generate the path.d value
55643  path = 'M' + points[0];
55644  for(i = 1; i < points.length; i++) {
55645    if (points[i].indexOf(',') !== -1) {
55646      path += 'L' + points[i];
55647    }
55648  }
55649  newElement.d = path;
55650  return newElement;
55651};
55652
55653/**
55654 * Read `polygon` element to extract and transform
55655 * data, to make it ready for a `path` object.
55656 * This method rely on polylineToPath, because the
55657 * logic is similar. The path created is just closed,
55658 * so it needs an 'Z' at the end.
55659 *
55660 * @param  {DOMelement} element Polygon element to transform
55661 * @return {object}             Data for a `path` element
55662 */
55663Pathformer.prototype.polygonToPath = function (element) {
55664  var newElement = Pathformer.prototype.polylineToPath(element);
55665
55666  newElement.d += 'Z';
55667  return newElement;
55668};
55669
55670/**
55671 * Read `ellipse` element to extract and transform
55672 * data, to make it ready for a `path` object.
55673 *
55674 * @param  {DOMelement} element ellipse element to transform
55675 * @return {object}             Data for a `path` element
55676 */
55677Pathformer.prototype.ellipseToPath = function (element) {
55678  var newElement = {},
55679      rx = parseFloat(element.rx) || 0,
55680      ry = parseFloat(element.ry) || 0,
55681      cx = parseFloat(element.cx) || 0,
55682      cy = parseFloat(element.cy) || 0,
55683      startX = cx - rx,
55684      startY = cy,
55685      endX = parseFloat(cx) + parseFloat(rx),
55686      endY = cy;
55687
55688  newElement.d = 'M' + startX + ',' + startY +
55689                 'A' + rx + ',' + ry + ' 0,1,1 ' + endX + ',' + endY +
55690                 'A' + rx + ',' + ry + ' 0,1,1 ' + startX + ',' + endY;
55691  return newElement;
55692};
55693
55694/**
55695 * Read `circle` element to extract and transform
55696 * data, to make it ready for a `path` object.
55697 *
55698 * @param  {DOMelement} element Circle element to transform
55699 * @return {object}             Data for a `path` element
55700 */
55701Pathformer.prototype.circleToPath = function (element) {
55702  var newElement = {},
55703      r  = parseFloat(element.r)  || 0,
55704      cx = parseFloat(element.cx) || 0,
55705      cy = parseFloat(element.cy) || 0,
55706      startX = cx - r,
55707      startY = cy,
55708      endX = parseFloat(cx) + parseFloat(r),
55709      endY = cy;
55710
55711  newElement.d =  'M' + startX + ',' + startY +
55712                  'A' + r + ',' + r + ' 0,1,1 ' + endX + ',' + endY +
55713                  'A' + r + ',' + r + ' 0,1,1 ' + startX + ',' + endY;
55714  return newElement;
55715};
55716
55717/**
55718 * Create `path` elements form original element
55719 * and prepared objects
55720 *
55721 * @param  {DOMelement} element  Original element to transform
55722 * @param  {object} pathData     Path data (from `toPath` methods)
55723 * @return {DOMelement}          Path element
55724 */
55725Pathformer.prototype.pathMaker = function (element, pathData) {
55726  var i, attr, pathTag = document.createElementNS('http://www.w3.org/2000/svg','path');
55727  for(i = 0; i < element.attributes.length; i++) {
55728    attr = element.attributes[i];
55729    if (this.ATTR_WATCH.indexOf(attr.name) === -1) {
55730      pathTag.setAttribute(attr.name, attr.value);
55731    }
55732  }
55733  for(i in pathData) {
55734    pathTag.setAttribute(i, pathData[i]);
55735  }
55736  return pathTag;
55737};
55738
55739/**
55740 * Parse attributes of a DOM element to
55741 * get an object of attribute => value
55742 *
55743 * @param  {NamedNodeMap} attributes Attributes object from DOM element to parse
55744 * @return {object}                  Object of attributes
55745 */
55746Pathformer.prototype.parseAttr = function (element) {
55747  var attr, output = {};
55748  for (var i = 0; i < element.length; i++) {
55749    attr = element[i];
55750    // Check if no data attribute contains '%', or the transformation is impossible
55751    if (this.ATTR_WATCH.indexOf(attr.name) !== -1 && attr.value.indexOf('%') !== -1) {
55752      throw new Error('Pathformer [parseAttr]: a SVG shape got values in percentage. This cannot be transformed into \'path\' tags. Please use \'viewBox\'.');
55753    }
55754    output[attr.name] = attr.value;
55755  }
55756  return output;
55757};
55758
55759  'use strict';
55760
55761var setupEnv, requestAnimFrame, cancelAnimFrame, parsePositiveInt;
55762
55763/**
55764 * Vivus
55765 * Beta version
55766 *
55767 * Take any SVG and make the animation
55768 * to give give the impression of live drawing
55769 *
55770 * This in more than just inspired from codrops
55771 * At that point, it's a pure fork.
55772 */
55773
55774/**
55775 * Class constructor
55776 * option structure
55777 *   type: 'delayed'|'sync'|'oneByOne'|'script' (to know if the items must be drawn synchronously or not, default: delayed)
55778 *   duration: <int> (in frames)
55779 *   start: 'inViewport'|'manual'|'autostart' (start automatically the animation, default: inViewport)
55780 *   delay: <int> (delay between the drawing of first and last path)
55781 *   dashGap <integer> whitespace extra margin between dashes
55782 *   pathTimingFunction <function> timing animation function for each path element of the SVG
55783 *   animTimingFunction <function> timing animation function for the complete SVG
55784 *   forceRender <boolean> force the browser to re-render all updated path items
55785 *   selfDestroy <boolean> removes all extra styling on the SVG, and leaves it as original
55786 *
55787 * The attribute 'type' is by default on 'delayed'.
55788 *  - 'delayed'
55789 *    all paths are draw at the same time but with a
55790 *    little delay between them before start
55791 *  - 'sync'
55792 *    all path are start and finish at the same time
55793 *  - 'oneByOne'
55794 *    only one path is draw at the time
55795 *    the end of the first one will trigger the draw
55796 *    of the next one
55797 *
55798 * All these values can be overwritten individually
55799 * for each path item in the SVG
55800 * The value of frames will always take the advantage of
55801 * the duration value.
55802 * If you fail somewhere, an error will be thrown.
55803 * Good luck.
55804 *
55805 * @constructor
55806 * @this {Vivus}
55807 * @param {DOM|String}   element  Dom element of the SVG or id of it
55808 * @param {Object}       options  Options about the animation
55809 * @param {Function}     callback Callback for the end of the animation
55810 */
55811function Vivus (element, options, callback) {
55812
55813  setupEnv();
55814
55815  // Setup
55816  this.isReady = false;
55817  this.setElement(element, options);
55818  this.setOptions(options);
55819  this.setCallback(callback);
55820
55821  if (this.isReady) {
55822    this.init();
55823  }
55824}
55825
55826/**
55827 * Timing functions
55828 **************************************
55829 *
55830 * Default functions to help developers.
55831 * It always take a number as parameter (between 0 to 1) then
55832 * return a number (between 0 and 1)
55833 */
55834Vivus.LINEAR          = function (x) {return x;};
55835Vivus.EASE            = function (x) {return -Math.cos(x * Math.PI) / 2 + 0.5;};
55836Vivus.EASE_OUT        = function (x) {return 1 - Math.pow(1-x, 3);};
55837Vivus.EASE_IN         = function (x) {return Math.pow(x, 3);};
55838Vivus.EASE_OUT_BOUNCE = function (x) {
55839  var base = -Math.cos(x * (0.5 * Math.PI)) + 1,
55840    rate = Math.pow(base,1.5),
55841    rateR = Math.pow(1 - x, 2),
55842    progress = -Math.abs(Math.cos(rate * (2.5 * Math.PI) )) + 1;
55843  return (1- rateR) + (progress * rateR);
55844};
55845
55846
55847/**
55848 * Setters
55849 **************************************
55850 */
55851
55852/**
55853 * Check and set the element in the instance
55854 * The method will not return anything, but will throw an
55855 * error if the parameter is invalid
55856 *
55857 * @param {DOM|String}   element  SVG Dom element or id of it
55858 */
55859Vivus.prototype.setElement = function (element, options) {
55860  var onLoad, self;
55861
55862  // Basic check
55863  if (typeof element === 'undefined') {
55864    throw new Error('Vivus [constructor]: "element" parameter is required');
55865  }
55866
55867  // Set the element
55868  if (element.constructor === String) {
55869    element = document.getElementById(element);
55870    if (!element) {
55871      throw new Error('Vivus [constructor]: "element" parameter is not related to an existing ID');
55872    }
55873  }
55874  this.parentEl = element;
55875
55876  // Load the SVG with XMLHttpRequest and extract the SVG
55877  if (options && options.file) {
55878    var self = this;
55879    onLoad = function (e) {
55880      var domSandbox = document.createElement('div');
55881      domSandbox.innerHTML = this.responseText;
55882
55883      var svgTag = domSandbox.querySelector('svg');
55884      if (!svgTag) {
55885        throw new Error('Vivus [load]: Cannot find the SVG in the loaded file : ' + options.file);
55886      }
55887
55888      self.el = svgTag
55889      self.el.setAttribute('width', '100%');
55890      self.el.setAttribute('height', '100%');
55891      self.parentEl.appendChild(self.el)
55892      self.isReady = true;
55893      self.init();
55894      self = null;
55895    }
55896
55897    var oReq = new window.XMLHttpRequest();
55898    oReq.addEventListener('load', onLoad);
55899    oReq.open('GET', options.file);
55900    oReq.send();
55901    return;
55902  }
55903
55904  switch (element.constructor) {
55905  case window.SVGSVGElement:
55906  case window.SVGElement:
55907  case window.SVGGElement:
55908    this.el = element;
55909    this.isReady = true;
55910    break;
55911
55912  case window.HTMLObjectElement:
55913    self = this;
55914    onLoad = function (e) {
55915      if (self.isReady) {
55916        return;
55917      }
55918      self.el = element.contentDocument && element.contentDocument.querySelector('svg');
55919      if (!self.el && e) {
55920        throw new Error('Vivus [constructor]: object loaded does not contain any SVG');
55921      }
55922      else if (self.el) {
55923        if (element.getAttribute('built-by-vivus')) {
55924          self.parentEl.insertBefore(self.el, element);
55925          self.parentEl.removeChild(element);
55926          self.el.setAttribute('width', '100%');
55927          self.el.setAttribute('height', '100%');
55928        }
55929        self.isReady = true;
55930        self.init();
55931        self = null;
55932      }
55933    };
55934
55935    if (!onLoad()) {
55936      element.addEventListener('load', onLoad);
55937    }
55938    break;
55939
55940  default:
55941    throw new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)');
55942  }
55943};
55944
55945/**
55946 * Set up user option to the instance
55947 * The method will not return anything, but will throw an
55948 * error if the parameter is invalid
55949 *
55950 * @param  {object} options Object from the constructor
55951 */
55952Vivus.prototype.setOptions = function (options) {
55953  var allowedTypes = ['delayed', 'sync', 'async', 'nsync', 'oneByOne', 'scenario', 'scenario-sync'];
55954  var allowedStarts =  ['inViewport', 'manual', 'autostart'];
55955
55956  // Basic check
55957  if (options !== undefined && options.constructor !== Object) {
55958    throw new Error('Vivus [constructor]: "options" parameter must be an object');
55959  }
55960  else {
55961    options = options || {};
55962  }
55963
55964  // Set the animation type
55965  if (options.type && allowedTypes.indexOf(options.type) === -1) {
55966    throw new Error('Vivus [constructor]: ' + options.type + ' is not an existing animation `type`');
55967  }
55968  else {
55969    this.type = options.type || allowedTypes[0];
55970  }
55971
55972  // Set the start type
55973  if (options.start && allowedStarts.indexOf(options.start) === -1) {
55974    throw new Error('Vivus [constructor]: ' + options.start + ' is not an existing `start` option');
55975  }
55976  else {
55977    this.start = options.start || allowedStarts[0];
55978  }
55979
55980  this.isIE         = (window.navigator.userAgent.indexOf('MSIE') !== -1 || window.navigator.userAgent.indexOf('Trident/') !== -1 || window.navigator.userAgent.indexOf('Edge/') !== -1 );
55981  this.duration     = parsePositiveInt(options.duration, 120);
55982  this.delay        = parsePositiveInt(options.delay, null);
55983  //Uncode addition
55984  this.delayStart   = parsePositiveInt(options.delayStart, null);
55985  //#END
55986  this.dashGap      = parsePositiveInt(options.dashGap, 1);
55987  this.forceRender  = options.hasOwnProperty('forceRender') ? !!options.forceRender : this.isIE;
55988  this.reverseStack = !!options.reverseStack;
55989  this.selfDestroy  = !!options.selfDestroy;
55990  this.onReady      = options.onReady;
55991  this.map          = [];
55992  this.frameLength  = this.currentFrame = this.delayUnit = this.speed = this.handle = null;
55993
55994  this.ignoreInvisible = options.hasOwnProperty('ignoreInvisible') ? !!options.ignoreInvisible : false;
55995
55996  this.animTimingFunction = options.animTimingFunction || Vivus.LINEAR;
55997  this.pathTimingFunction = options.pathTimingFunction || Vivus.LINEAR;
55998
55999  if (this.delay >= this.duration) {
56000    throw new Error('Vivus [constructor]: delay must be shorter than duration');
56001  }
56002};
56003
56004/**
56005 * Set up callback to the instance
56006 * The method will not return enything, but will throw an
56007 * error if the parameter is invalid
56008 *
56009 * @param  {Function} callback Callback for the animation end
56010 */
56011Vivus.prototype.setCallback = function (callback) {
56012  // Basic check
56013  if (!!callback && callback.constructor !== Function) {
56014    throw new Error('Vivus [constructor]: "callback" parameter must be a function');
56015  }
56016  this.callback = callback || function () {};
56017};
56018
56019
56020/**
56021 * Core
56022 **************************************
56023 */
56024
56025/**
56026 * Map the svg, path by path.
56027 * The method return nothing, it just fill the
56028 * `map` array. Each item in this array represent
56029 * a path element from the SVG, with informations for
56030 * the animation.
56031 *
56032 * ```
56033 * [
56034 *   {
56035 *     el: <DOMobj> the path element
56036 *     length: <number> length of the path line
56037 *     startAt: <number> time start of the path animation (in frames)
56038 *     duration: <number> path animation duration (in frames)
56039 *   },
56040 *   ...
56041 * ]
56042 * ```
56043 *
56044 */
56045Vivus.prototype.mapping = function () {
56046  var i, paths, path, pAttrs, pathObj, totalLength, lengthMeter, timePoint;
56047  timePoint = totalLength = lengthMeter = 0;
56048  paths = this.el.querySelectorAll('path');
56049
56050  for (i = 0; i < paths.length; i++) {
56051    path = paths[i];
56052    if (this.isInvisible(path)) {
56053      continue;
56054    }
56055    pathObj = {
56056      el: path,
56057      length: Math.ceil(path.getTotalLength())
56058    };
56059    // Test if the path length is correct
56060    if (isNaN(pathObj.length)) {
56061      if (window.console && console.warn) {
56062        console.warn('Vivus [mapping]: cannot retrieve a path element length', path);
56063      }
56064      continue;
56065    }
56066    this.map.push(pathObj);
56067    path.style.strokeDasharray  = pathObj.length + ' ' + (pathObj.length + this.dashGap * 2);
56068    path.style.strokeDashoffset = pathObj.length + this.dashGap;
56069    pathObj.length += this.dashGap;
56070    totalLength += pathObj.length;
56071
56072    this.renderPath(i);
56073  }
56074
56075  totalLength = totalLength === 0 ? 1 : totalLength;
56076  this.delay = this.delay === null ? this.duration / 3 : this.delay;
56077  this.delayUnit = this.delay / (paths.length > 1 ? paths.length - 1 : 1);
56078
56079  // Reverse stack if asked
56080  if (this.reverseStack) {
56081    this.map.reverse();
56082  }
56083
56084  for (i = 0; i < this.map.length; i++) {
56085    pathObj = this.map[i];
56086
56087    switch (this.type) {
56088    case 'delayed':
56089      pathObj.startAt = this.delayUnit * i;
56090      pathObj.duration = this.duration - this.delay;
56091      break;
56092
56093    case 'oneByOne':
56094      pathObj.startAt = lengthMeter / totalLength * this.duration;
56095      pathObj.duration = pathObj.length / totalLength * this.duration;
56096      break;
56097
56098    case 'sync':
56099    case 'async':
56100    case 'nsync':
56101      pathObj.startAt = 0;
56102      pathObj.duration = this.duration;
56103      break;
56104
56105    case 'scenario-sync':
56106      path = pathObj.el;
56107      pAttrs = this.parseAttr(path);
56108      pathObj.startAt = timePoint + (parsePositiveInt(pAttrs['data-delay'], this.delayUnit) || 0);
56109      pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
56110      timePoint = pAttrs['data-async'] !== undefined ? pathObj.startAt : pathObj.startAt + pathObj.duration;
56111      this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
56112      break;
56113
56114    case 'scenario':
56115      path = pathObj.el;
56116      pAttrs = this.parseAttr(path);
56117      pathObj.startAt = parsePositiveInt(pAttrs['data-start'], this.delayUnit) || 0;
56118      pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
56119      this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
56120      break;
56121    }
56122    lengthMeter += pathObj.length;
56123    this.frameLength = this.frameLength || this.duration;
56124  }
56125};
56126
56127/**
56128 * Interval method to draw the SVG from current
56129 * position of the animation. It update the value of
56130 * `currentFrame` and re-trace the SVG.
56131 *
56132 * It use this.handle to store the requestAnimationFrame
56133 * and clear it one the animation is stopped. So this
56134 * attribute can be used to know if the animation is
56135 * playing.
56136 *
56137 * Once the animation at the end, this method will
56138 * trigger the Vivus callback.
56139 *
56140 */
56141Vivus.prototype.drawer = function () {
56142  var self = this;
56143  this.currentFrame += this.speed;
56144
56145  if (this.currentFrame <= 0) {
56146    this.stop();
56147    this.reset();
56148  } else if (this.currentFrame >= this.frameLength) {
56149    this.stop();
56150    this.currentFrame = this.frameLength;
56151    this.trace();
56152    if (this.selfDestroy) {
56153      this.destroy();
56154    }
56155  } else {
56156    this.trace();
56157    this.handle = requestAnimFrame(function () {
56158      self.drawer();
56159    });
56160    return;
56161  }
56162
56163  this.callback(this);
56164  if (this.instanceCallback) {
56165    this.instanceCallback(this);
56166    this.instanceCallback = null;
56167  }
56168};
56169
56170/**
56171 * Draw the SVG at the current instant from the
56172 * `currentFrame` value. Here is where most of the magic is.
56173 * The trick is to use the `strokeDashoffset` style property.
56174 *
56175 * For optimisation reasons, a new property called `progress`
56176 * is added in each item of `map`. This one contain the current
56177 * progress of the path element. Only if the new value is different
56178 * the new value will be applied to the DOM element. This
56179 * method save a lot of resources to re-render the SVG. And could
56180 * be improved if the animation couldn't be played forward.
56181 *
56182 */
56183Vivus.prototype.trace = function () {
56184  var i, progress, path, currentFrame;
56185  currentFrame = this.animTimingFunction(this.currentFrame / this.frameLength) * this.frameLength;
56186  for (i = 0; i < this.map.length; i++) {
56187    path = this.map[i];
56188    progress = (currentFrame - path.startAt) / path.duration;
56189    progress = this.pathTimingFunction(Math.max(0, Math.min(1, progress)));
56190    if (path.progress !== progress) {
56191      path.progress = progress;
56192      path.el.style.strokeDashoffset = Math.floor(path.length * (1 - progress));
56193      this.renderPath(i);
56194    }
56195  }
56196};
56197
56198/**
56199 * Method forcing the browser to re-render a path element
56200 * from it's index in the map. Depending on the `forceRender`
56201 * value.
56202 * The trick is to replace the path element by it's clone.
56203 * This practice is not recommended because it's asking more
56204 * ressources, too much DOM manupulation..
56205 * but it's the only way to let the magic happen on IE.
56206 * By default, this fallback is only applied on IE.
56207 *
56208 * @param  {Number} index Path index
56209 */
56210Vivus.prototype.renderPath = function (index) {
56211  if (this.forceRender && this.map && this.map[index]) {
56212    var pathObj = this.map[index],
56213        newPath = pathObj.el.cloneNode(true);
56214    pathObj.el.parentNode.replaceChild(newPath, pathObj.el);
56215    pathObj.el = newPath;
56216  }
56217};
56218
56219/**
56220 * When the SVG object is loaded and ready,
56221 * this method will continue the initialisation.
56222 *
56223 * This this mainly due to the case of passing an
56224 * object tag in the constructor. It will wait
56225 * the end of the loading to initialise.
56226 *
56227 */
56228Vivus.prototype.init = function () {
56229  // Set object variables
56230  this.frameLength = 0;
56231  this.currentFrame = 0;
56232  this.map = [];
56233
56234  // Start
56235  new Pathformer(this.el);
56236  this.mapping();
56237  this.starter();
56238
56239  if (this.onReady) {
56240    this.onReady(this);
56241  }
56242};
56243
56244/**
56245 * Trigger to start of the animation.
56246 * Depending on the `start` value, a different script
56247 * will be applied.
56248 *
56249 * If the `start` value is not valid, an error will be thrown.
56250 * Even if technically, this is impossible.
56251 *
56252 */
56253Vivus.prototype.starter = function () {
56254  switch (this.start) {
56255  case 'manual':
56256    return;
56257
56258  case 'autostart':
56259    this.play();
56260    break;
56261
56262  case 'inViewport':
56263    var self = this,
56264    listener = function () {
56265      if (self.isInViewport(self.parentEl, 1)) {
56266        self.play();
56267        window.removeEventListener('scroll', listener);
56268        //Uncode addition
56269        window.removeEventListener('fp-slide-changed', listener);
56270        window.removeEventListener('fp-slide-scroll', listener);
56271        //#END
56272      }
56273    };
56274    window.addEventListener('scroll', listener);
56275    //Uncode addition
56276    window.addEventListener('fp-slide-changed', listener);
56277    window.addEventListener('fp-slide-scroll', listener);
56278    //#END
56279    listener();
56280    break;
56281  }
56282};
56283
56284
56285/**
56286 * Controls
56287 **************************************
56288 */
56289
56290/**
56291 * Get the current status of the animation between
56292 * three different states: 'start', 'progress', 'end'.
56293 * @return {string} Instance status
56294 */
56295Vivus.prototype.getStatus = function () {
56296  return this.currentFrame === 0 ? 'start' : this.currentFrame === this.frameLength ? 'end' : 'progress';
56297};
56298
56299/**
56300 * Reset the instance to the initial state : undraw
56301 * Be careful, it just reset the animation, if you're
56302 * playing the animation, this won't stop it. But just
56303 * make it start from start.
56304 *
56305 */
56306Vivus.prototype.reset = function () {
56307  return this.setFrameProgress(0);
56308};
56309
56310/**
56311 * Set the instance to the final state : drawn
56312 * Be careful, it just set the animation, if you're
56313 * playing the animation on rewind, this won't stop it.
56314 * But just make it start from the end.
56315 *
56316 */
56317Vivus.prototype.finish = function () {
56318  return this.setFrameProgress(1);
56319};
56320
56321/**
56322 * Set the level of progress of the drawing.
56323 *
56324 * @param {number} progress Level of progress to set
56325 */
56326Vivus.prototype.setFrameProgress = function (progress) {
56327  progress = Math.min(1, Math.max(0, progress));
56328  this.currentFrame = Math.round(this.frameLength * progress);
56329  this.trace();
56330  return this;
56331};
56332
56333/**
56334 * Play the animation at the desired speed.
56335 * Speed must be a valid number (no zero).
56336 * By default, the speed value is 1.
56337 * But a negative value is accepted to go forward.
56338 *
56339 * And works with float too.
56340 * But don't forget we are in JavaScript, se be nice
56341 * with him and give him a 1/2^x value.
56342 *
56343 * @param  {number} speed Animation speed [optional]
56344 */
56345Vivus.prototype.play = function (speed, callback) {
56346  this.instanceCallback = null;
56347
56348  if (speed && typeof speed === 'function') {
56349    this.instanceCallback = speed; // first parameter is actually the callback function
56350    speed = null;
56351  }
56352  else if (speed && typeof speed !== 'number') {
56353    throw new Error('Vivus [play]: invalid speed');
56354  }
56355  // if the first parameter wasn't the callback, check if the seconds was
56356  if (callback && typeof(callback) === 'function' && !this.instanceCallback) {
56357    this.instanceCallback = callback;
56358  }
56359
56360
56361  this.speed = speed || 1;
56362  //Uncode addition
56363  if (!this.handle) {
56364    var $this = this,
56365    delay = (this.delayStart != null) ? this.delayStart : 0;
56366    setTimeout(function() {
56367      $this.drawer();
56368    }, delay);
56369  }
56370  //#END
56371  return this;
56372};
56373
56374/**
56375 * Stop the current animation, if on progress.
56376 * Should not trigger any error.
56377 *
56378 */
56379Vivus.prototype.stop = function () {
56380  if (this.handle) {
56381    cancelAnimFrame(this.handle);
56382    this.handle = null;
56383  }
56384  return this;
56385};
56386
56387/**
56388 * Destroy the instance.
56389 * Remove all bad styling attributes on all
56390 * path tags
56391 *
56392 */
56393Vivus.prototype.destroy = function () {
56394  this.stop();
56395  var i, path;
56396  for (i = 0; i < this.map.length; i++) {
56397    path = this.map[i];
56398    path.el.style.strokeDashoffset = null;
56399    path.el.style.strokeDasharray = null;
56400    this.renderPath(i);
56401  }
56402};
56403
56404
56405/**
56406 * Utils methods
56407 * include methods from Codrops
56408 **************************************
56409 */
56410
56411/**
56412 * Method to best guess if a path should added into
56413 * the animation or not.
56414 *
56415 * 1. Use the `data-vivus-ignore` attribute if set
56416 * 2. Check if the instance must ignore invisible paths
56417 * 3. Check if the path is visible
56418 *
56419 * For now the visibility checking is unstable.
56420 * It will be used for a beta phase.
56421 *
56422 * Other improvments are planned. Like detecting
56423 * is the path got a stroke or a valid opacity.
56424 */
56425Vivus.prototype.isInvisible = function (el) {
56426  var rect,
56427    ignoreAttr = el.getAttribute('data-ignore');
56428
56429  if (ignoreAttr !== null) {
56430    return ignoreAttr !== 'false';
56431  }
56432
56433  if (this.ignoreInvisible) {
56434    rect = el.getBoundingClientRect();
56435    return !rect.width && !rect.height;
56436  }
56437  else {
56438    return false;
56439  }
56440};
56441
56442/**
56443 * Parse attributes of a DOM element to
56444 * get an object of {attributeName => attributeValue}
56445 *
56446 * @param  {object} element DOM element to parse
56447 * @return {object}         Object of attributes
56448 */
56449Vivus.prototype.parseAttr = function (element) {
56450  var attr, output = {};
56451  if (element && element.attributes) {
56452    for (var i = 0; i < element.attributes.length; i++) {
56453      attr = element.attributes[i];
56454      output[attr.name] = attr.value;
56455    }
56456  }
56457  return output;
56458};
56459
56460/**
56461 * Reply if an element is in the page viewport
56462 *
56463 * @param  {object} el Element to observe
56464 * @param  {number} h  Percentage of height
56465 * @return {boolean}
56466 */
56467Vivus.prototype.isInViewport = function (el, h) {
56468  var scrolled   = this.scrollY(),
56469    viewed       = scrolled + this.getViewportH(),
56470    elBCR        = el.getBoundingClientRect(),
56471    elHeight     = elBCR.height,
56472    elTop        = scrolled + elBCR.top,
56473    elBottom     = elTop + elHeight;
56474
56475  // if 0, the element is considered in the viewport as soon as it enters.
56476  // if 1, the element is considered in the viewport only when it's fully inside
56477  // value in percentage (1 >= h >= 0)
56478  h = h || 0;
56479
56480  return (elTop + elHeight * h) <= viewed && (elBottom) >= scrolled;
56481};
56482
56483
56484/**
56485 * Get the viewport height in pixels
56486 *
56487 * @return {integer} Viewport height
56488 */
56489Vivus.prototype.getViewportH = function () {
56490  var client = this.docElem.clientHeight,
56491    inner = window.innerHeight;
56492
56493  if (client < inner) {
56494    return inner;
56495  }
56496  else {
56497    return client;
56498  }
56499};
56500
56501/**
56502 * Get the page Y offset
56503 *
56504 * @return {integer} Page Y offset
56505 */
56506Vivus.prototype.scrollY = function () {
56507  return window.pageYOffset || this.docElem.scrollTop;
56508};
56509
56510setupEnv = function () {
56511
56512  if (Vivus.prototype.docElem) {
56513    return;
56514  }
56515
56516  /**
56517   * Alias for document element
56518   *
56519   * @type {DOMelement}
56520   */
56521  Vivus.prototype.docElem = window.document.documentElement;
56522
56523  /**
56524   * Alias for `requestAnimationFrame` or
56525   * `setTimeout` function for deprecated browsers.
56526   *
56527   */
56528  requestAnimFrame = (function () {
56529    return (
56530      window.requestAnimationFrame       ||
56531      window.webkitRequestAnimationFrame ||
56532      window.mozRequestAnimationFrame    ||
56533      window.oRequestAnimationFrame      ||
56534      window.msRequestAnimationFrame     ||
56535      function(/* function */ callback){
56536        return window.setTimeout(callback, 1000 / 60);
56537      }
56538    );
56539  })();
56540
56541  /**
56542   * Alias for `cancelAnimationFrame` or
56543   * `cancelTimeout` function for deprecated browsers.
56544   *
56545   */
56546  cancelAnimFrame = (function () {
56547    return (
56548      window.cancelAnimationFrame       ||
56549      window.webkitCancelAnimationFrame ||
56550      window.mozCancelAnimationFrame    ||
56551      window.oCancelAnimationFrame      ||
56552      window.msCancelAnimationFrame     ||
56553      function(id){
56554        return window.clearTimeout(id);
56555      }
56556    );
56557  })();
56558};
56559
56560/**
56561 * Parse string to integer.
56562 * If the number is not positive or null
56563 * the method will return the default value
56564 * or 0 if undefined
56565 *
56566 * @param {string} value String to parse
56567 * @param {*}
56567 defaultValue Value to return if the result parsed is invalid
56568 * @return {number}
56569 *
56570 */
56571parsePositiveInt = function (value, defaultValue) {
56572  var output = parseInt(value, 10);
56573  return (output >= 0) ? output : defaultValue;
56574};
56575
56576
56577  if (typeof define === 'function' && define.amd) {
56578    // AMD. Register as an anonymous module.
56579    define([], function() {
56580      return Vivus;
56581    });
56582  } else if (typeof exports === 'object') {
56583    // Node. Does not work with strict CommonJS, but
56584    // only CommonJS-like environments that support module.exports,
56585    // like Node.
56586    module.exports = Vivus;
56587  } else {
56588    // Browser globals
56589    window.Vivus = Vivus;
56590  }
56591
56592}());
56593
56594//Noise.js
56595!function(){"use strict";var r=.5*(Math.sqrt(3)-1),e=(3-Math.sqrt(3))/6,t=1/6,a=(Math.sqrt(5)-1)/4,o=(5-Math.sqrt(5))/20;function i(r){var e;e="function"==typeof r?r:r?function(){var r=0,e=0,t=0,a=1,o=(i=4022871197,function(r){r=r.toString();for(var e=0;e<r.length;e++){var t=.02519603282416938*(i+=r.charCodeAt(e));t-=i=t>>>0,i=(t*=i)>>>0,i+=4294967296*(t-=i)}return 2.3283064365386963e-10*(i>>>0)});var i;r=o(" "),e=o(" "),t=o(" ");for(var n=0;n<arguments.length;n++)(r-=o(arguments[n]))<0&&(r+=1),(e-=o(arguments[n]))<0&&(e+=1),(t-=o(arguments[n]))<0&&(t+=1);return o=null,function(){var o=2091639*r+2.3283064365386963e-10*a;return r=e,e=t,t=o-(a=0|o)}}(r):Math.random,this.p=n(e),this.perm=new Uint8Array(512),this.permMod12=new Uint8Array(512);for(var t=0;t<512;t++)this.perm[t]=this.p[255&t],this.permMod12[t]=this.perm[t]%12}function n(r){var e,t=new Uint8Array(256);for(e=0;e<256;e++)t[e]=e;for(e=0;e<255;e++){var a=e+~~(r()*(256-e)),o=t[e];t[e]=t[a],t[a]=o}return t}i.prototype={grad3:new Float32Array([1,1,0,-1,1,0,1,-1,0,-1,-1,0,1,0,1,-1,0,1,1,0,-1,-1,0,-1,0,1,1,0,-1,1,0,1,-1,0,-1,-1]),grad4:new Float32Array([0,1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1,0,-1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1,1,0,1,1,1,0,1,-1,1,0,-1,1,1,0,-1,-1,-1,0,1,1,-1,0,1,-1,-1,0,-1,1,-1,0,-1,-1,1,1,0,1,1,1,0,-1,1,-1,0,1,1,-1,0,-1,-1,1,0,1,-1,1,0,-1,-1,-1,0,1,-1,-1,0,-1,1,1,1,0,1,1,-1,0,1,-1,1,0,1,-1,-1,0,-1,1,1,0,-1,1,-1,0,-1,-1,1,0,-1,-1,-1,0]),noise2D:function(t,a){var o,i,n=this.permMod12,f=this.perm,s=this.grad3,v=0,h=0,l=0,u=(t+a)*r,d=Math.floor(t+u),p=Math.floor(a+u),M=(d+p)*e,m=t-(d-M),c=a-(p-M);m>c?(o=1,i=0):(o=0,i=1);var y=m-o+e,w=c-i+e,g=m-1+2*e,A=c-1+2*e,x=255&d,q=255&p,D=.5-m*m-c*c;if(D>=0){var S=3*n[x+f[q]];v=(D*=D)*D*(s[S]*m+s[S+1]*c)}var U=.5-y*y-w*w;if(U>=0){var b=3*n[x+o+f[q+i]];h=(U*=U)*U*(s[b]*y+s[b+1]*w)}var F=.5-g*g-A*A;if(F>=0){var N=3*n[x+1+f[q+1]];l=(F*=F)*F*(s[N]*g+s[N+1]*A)}return 70*(v+h+l)},noise3D:function(r,e,a){var o,i,n,f,s,v,h,l,u,d,p=this.permMod12,M=this.perm,m=this.grad3,c=(r+e+a)*(1/3),y=Math.floor(r+c),w=Math.floor(e+c),g=Math.floor(a+c),A=(y+w+g)*t,x=r-(y-A),q=e-(w-A),D=a-(g-A);x>=q?q>=D?(s=1,v=0,h=0,l=1,u=1,d=0):x>=D?(s=1,v=0,h=0,l=1,u=0,d=1):(s=0,v=0,h=1,l=1,u=0,d=1):q<D?(s=0,v=0,h=1,l=0,u=1,d=1):x<D?(s=0,v=1,h=0,l=0,u=1,d=1):(s=0,v=1,h=0,l=1,u=1,d=0);var S=x-s+t,U=q-v+t,b=D-h+t,F=x-l+2*t,N=q-u+2*t,C=D-d+2*t,P=x-1+.5,T=q-1+.5,_=D-1+.5,j=255&y,k=255&w,z=255&g,B=.6-x*x-q*q-D*D;if(B<0)o=0;else{var E=3*p[j+M[k+M[z]]];o=(B*=B)*B*(m[E]*x+m[E+1]*q+m[E+2]*D)}var G=.6-S*S-U*U-b*b;if(G<0)i=0;else{var H=3*p[j+s+M[k+v+M[z+h]]];i=(G*=G)*G*(m[H]*S+m[H+1]*U+m[H+2]*b)}var I=.6-F*F-N*N-C*C;if(I<0)n=0;else{var J=3*p[j+l+M[k+u+M[z+d]]];n=(I*=I)*I*(m[J]*F+m[J+1]*N+m[J+2]*C)}var K=.6-P*P-T*T-_*_;if(K<0)f=0;else{var L=3*p[j+1+M[k+1+M[z+1]]];f=(K*=K)*K*(m[L]*P+m[L+1]*T+m[L+2]*_)}return 32*(o+i+n+f)},noise4D:function(r,e,t,i){var n,f,s,v,h,l,u,d,p,M,m,c,y,w,g,A,x,q=this.perm,D=this.grad4,S=(r+e+t+i)*a,U=Math.floor(r+S),b=Math.floor(e+S),F=Math.floor(t+S),N=Math.floor(i+S),C=(U+b+F+N)*o,P=r-(U-C),T=e-(b-C),_=t-(F-C),j=i-(N-C),k=0,z=0,B=0,E=0;P>T?k++:z++,P>_?k++:B++,P>j?k++:E++,T>_?z++:B++,T>j?z++:E++,_>j?B++:E++;var G=P-(l=k>=3?1:0)+o,H=T-(u=z>=3?1:0)+o,I=_-(d=B>=3?1:0)+o,J=j-(p=E>=3?1:0)+o,K=P-(M=k>=2?1:0)+2*o,L=T-(m=z>=2?1:0)+2*o,O=_-(c=B>=2?1:0)+2*o,Q=j-(y=E>=2?1:0)+2*o,R=P-(w=k>=1?1:0)+3*o,V=T-(g=z>=1?1:0)+3*o,W=_-(A=B>=1?1:0)+3*o,X=j-(x=E>=1?1:0)+3*o,Y=P-1+4*o,Z=T-1+4*o,$=_-1+4*o,rr=j-1+4*o,er=255&U,tr=255&b,ar=255&F,or=255&N,ir=.6-P*P-T*T-_*_-j*j;if(ir<0)n=0;else{var nr=q[er+q[tr+q[ar+q[or]]]]%32*4;n=(ir*=ir)*ir*(D[nr]*P+D[nr+1]*T+D[nr+2]*_+D[nr+3]*j)}var fr=.6-G*G-H*H-I*I-J*J;if(fr<0)f=0;else{var sr=q[er+l+q[tr+u+q[ar+d+q[or+p]]]]%32*4;f=(fr*=fr)*fr*(D[sr]*G+D[sr+1]*H+D[sr+2]*I+D[sr+3]*J)}var vr=.6-K*K-L*L-O*O-Q*Q;if(vr<0)s=0;else{var hr=q[er+M+q[tr+m+q[ar+c+q[or+y]]]]%32*4;s=(vr*=vr)*vr*(D[hr]*K+D[hr+1]*L+D[hr+2]*O+D[hr+3]*Q)}
56595var lr=.6-R*R-V*V-W*W-X*X;if(lr<0)v=0;else{var ur=q[er+w+q[tr+g+q[ar+A+q[or+x]]]]%32*4;v=(lr*=lr)*lr*(D[ur]*R+D[ur+1]*V+D[ur+2]*W+D[ur+3]*X)}var dr=.6-Y*Y-Z*Z-$*$-rr*rr;if(dr<0)h=0;else{var pr=q[er+1+q[tr+1+q[ar+1+q[or+1]]]]%32*4;h=(dr*=dr)*dr*(D[pr]*Y+D[pr+1]*Z+D[pr+2]*$+D[pr+3]*rr)}return 27*(n+f+s+v+h)}},i._buildPermutationTable=n,"undefined"!=typeof define&&define.amd&&define(function(){return i}),"undefined"!=typeof exports?exports.SimplexNoise=i:"undefined"!=typeof window&&(window.SimplexNoise=i),"undefined"!=typeof module&&(module.exports=i)}();

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.