PageSourceSearch

https://michaelnye.org/wp-content/themes/uncode/library/js/plugins.js?ver=241570927

js michaelnye.org collected 2026-10-02 05:55:23 UTC 951,309 bytes, 29,311 lines download raw bytes

vendor: 4,719 bytes, lines 1-147
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.6.1
27   * https://greensock.com
28   *
29   * @license Copyright 2008-2021, GreenSock. All rights reserved.
30   * Subject to the terms at https://greensock.com/standard-license or for
31   * Club GreenSock 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      _bigNum = 1e8,
49      _tinyNum = 1 / _bigNum,
50      _2PI = Math.PI * 2,
51      _HALF_PI = _2PI / 4,
52      _gsID = 0,
53      _sqrt = Math.sqrt,
54      _cos = Math.cos,
55      _sin = Math.sin,
56      _isString = function _isString(value) {
57    return typeof value === "string";
58  },
59      _isFunction = function _isFunction(value) {
60    return typeof value === "function";
61  },
62      _isNumber = function _isNumber(value) {
63    return typeof value === "number";
64  },
65      _isUndefined = function _isUndefined(value) {
66    return typeof value === "undefined";
67  },
68      _isObject = function _isObject(value) {
69    return typeof value === "object";
70  },
71      _isNotFalse = function _isNotFalse(value) {
72    return value !== false;
73  },
74      _windowExists = function _windowExists() {
75    return typeof window !== "undefined";
76  },
77      _isFuncOrString = function _isFuncOrString(value) {
78    return _isFunction(value) || _isString(value);
79  },
80      _isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView || function () {},
81      _isArray = Array.isArray,
82      _strictNumExp = /(?:-?\.?\d|\.)+/gi,
83      _numExp = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/g,
84      _numWithUnitExp = /[-+=.]*\d+[.e-]*\d*[a-z%]*/g,
85      _complexStringNumExp = /[-+=.]*\d+\.?\d*(?:e-|e\+)?\d*/gi,
86      _relExp = /[+-]=-?[.\d]+/,
87      _delimitedValueExp = /[#\-+.]*\b[a-z\d-=+%.]+/gi,
88      _unitExp = /[\d.+\-=]+(?:e[-+]\d*)*/i,
89      _globalTimeline,
90      _win,
91      _coreInitted,
92      _doc,
93      _globals = {},
94      _installScope = {},
95      _coreReady,
96      _install = function _install(scope) {
97    return (_installScope = _merge(scope, _globals)) && gsap;
98  },
99      _missingPlugin = function _missingPlugin(property, value) {
100    return console.warn("Invalid property", property, "set to", value, "Missing plugin? gsap.registerPlugin()");
101  },
102      _warn = function _warn(message, suppress) {
103    return !suppress && console.warn(message);
104  },
105      _addGlobal = function _addGlobal(name, obj) {
106    return name && (_globals[name] = obj) && _installScope && (_installScope[name] = obj) || _globals;
107  },
108      _emptyFunc = function _emptyFunc() {
109    return 0;
110  },
111      _reservedProps = {},
112      _lazyTweens = [],
113      _lazyLookup = {},
114      _lastRenderedFrame,
115      _plugins = {},
116      _effects = {},
117      _nextGCFrame = 30,
118      _harnessPlugins = [],
119      _callbackNames = "",
120      _harness = function _harness(targets) {
121    var target = targets[0],
122        harnessPlugin,
123        i;
124    _isObject(target) || _isFunction(target) || (targets = [targets]);
125
126    if (!(harnessPlugin = (target._gsap || {}).harness)) {
127      i = _harnessPlugins.length;
128
129      while (i-- && !_harnessPlugins[i].targetTest(target)) {}
130
131      harnessPlugin = _harnessPlugins[i];
132    }
133
134    i = targets.length;
135
136    while (i--) {
137      targets[i] && (targets[i]._gsap || (targets[i]._gsap = new GSCache(targets[i], harnessPlugin))) || targets.splice(i, 1);
138    }
139
140    return targets;
141  },
142      _getCache = function _getCache(target) {
143    return target._gsap || _harness(toArray(target))[0]._gsap;
144  },
145      _getProperty = function _getProperty(target, property, v) {
146    return (v = target[property]) && _isFunction(v) ? target[property]() : _isUndefined(v) && target.getAttribute && target.getAttribute(property) || v;
147  },
vendor: 7,717 bytes, lines 148-411
148      _forEachName = function _forEachName(names, func) {
149    return (names = names.split(",")).forEach(func) || names;
150  },
151      _round = function _round(value) {
152    return Math.round(value * 100000) / 100000 || 0;
153  },
154      _arrayContainsAny = function _arrayContainsAny(toSearch, toFind) {
155    var l = toFind.length,
156        i = 0;
157
158    for (; toSearch.indexOf(toFind[i]) < 0 && ++i < l;) {}
159
160    return i < l;
161  },
162      _parseVars = function _parseVars(params, type, parent) {
163    var isLegacy = _isNumber(params[1]),
164        varsIndex = (isLegacy ? 2 : 1) + (type < 2 ? 0 : 1),
165        vars = params[varsIndex],
166        irVars;
167
168    isLegacy && (vars.duration = params[1]);
169    vars.parent = parent;
170
171    if (type) {
172      irVars = vars;
173
174      while (parent && !("immediateRender" in irVars)) {
175        irVars = parent.vars.defaults || {};
176        parent = _isNotFalse(parent.vars.inherit) && parent.parent;
177      }
178
179      vars.immediateRender = _isNotFalse(irVars.immediateRender);
180      type < 2 ? vars.runBackwards = 1 : vars.startAt = params[varsIndex - 1];
181    }
182
183    return vars;
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 && _lazyRender();
201    animation.render(time, suppressEvents, force);
202    _lazyTweens.length && _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(obj, defaults) {
219    for (var p in defaults) {
220      p in obj || p === "duration" || p === "ease" || (obj[p] = defaults[p]);
221    }
222  },
223      _merge = function _merge(base, toMerge) {
224    for (var p in toMerge) {
225      base[p] = toMerge[p];
226    }
227
228    return base;
229  },
230      _mergeDeep = function _mergeDeep(base, toMerge) {
231    for (var p in toMerge) {
232      p !== "__proto__" && p !== "constructor" && p !== "prototype" && (base[p] = _isObject(toMerge[p]) ? _mergeDeep(base[p] || (base[p] = {}), toMerge[p]) : toMerge[p]);
233    }
234
235    return base;
236  },
237      _copyExcluding = function _copyExcluding(obj, excluding) {
238    var copy = {},
239        p;
240
241    for (p in obj) {
242      p in excluding || (copy[p] = obj[p]);
243    }
244
245    return copy;
246  },
247      _inheritDefaults = function _inheritDefaults(vars) {
248    var parent = vars.parent || _globalTimeline,
249        func = vars.keyframes ? _setKeyframeDefaults : _setDefaults;
250
251    if (_isNotFalse(vars.inherit)) {
252      while (parent) {
253        func(vars, parent.vars.defaults);
254        parent = parent.parent || parent._dp;
255      }
256    }
257
258    return vars;
259  },
260      _arraysMatch = function _arraysMatch(a1, a2) {
261    var i = a1.length,
262        match = i === a2.length;
263
264    while (match && i-- && a1[i] === a2[i]) {}
265
266    return i < 0;
267  },
268      _addLinkedListItem = function _addLinkedListItem(parent, child, firstProp, lastProp, sortBy) {
269    if (firstProp === void 0) {
270      firstProp = "_first";
271    }
272
273    if (lastProp === void 0) {
274      lastProp = "_last";
275    }
276
277    var prev = parent[lastProp],
278        t;
279
280    if (sortBy) {
281      t = child[sortBy];
282
283      while (prev && prev[sortBy] > t) {
284        prev = prev._prev;
285      }
286    }
287
288    if (prev) {
289      child._next = prev._next;
290      prev._next = child;
291    } else {
292      child._next = parent[firstProp];
293      parent[firstProp] = child;
294    }
295
296    if (child._next) {
297      child._next._prev = child;
298    } else {
299      parent[lastProp] = child;
300    }
301
302    child._prev = prev;
303    child.parent = child._dp = parent;
304    return child;
305  },
306      _removeLinkedListItem = function _removeLinkedListItem(parent, child, firstProp, lastProp) {
307    if (firstProp === void 0) {
308      firstProp = "_first";
309    }
310
311    if (lastProp === void 0) {
312      lastProp = "_last";
313    }
314
315    var prev = child._prev,
316        next = child._next;
317
318    if (prev) {
319      prev._next = next;
320    } else if (parent[firstProp] === child) {
321      parent[firstProp] = next;
322    }
323
324    if (next) {
325      next._prev = prev;
326    } else if (parent[lastProp] === child) {
327      parent[lastProp] = prev;
328    }
329
330    child._next = child._prev = child.parent = null;
331  },
332      _removeFromParent = function _removeFromParent(child, onlyIfParentHasAutoRemove) {
333    child.parent && (!onlyIfParentHasAutoRemove || child.parent.autoRemoveChildren) && child.parent.remove(child);
334    child._act = 0;
335  },
336      _uncache = function _uncache(animation, child) {
337    if (animation && (!child || child._end > animation._dur || child._start < 0)) {
338      var a = animation;
339
340      while (a) {
341        a._dirty = 1;
342        a = a.parent;
343      }
344    }
345
346    return animation;
347  },
348      _recacheAncestors = function _recacheAncestors(animation) {
349    var parent = animation.parent;
350
351    while (parent && parent.parent) {
352      parent._dirty = 1;
353      parent.totalDuration();
354      parent = parent.parent;
355    }
356
357    return animation;
358  },
359      _hasNoPausedAncestors = function _hasNoPausedAncestors(animation) {
360    return !animation || animation._ts && _hasNoPausedAncestors(animation.parent);
361  },
362      _elapsedCycleDuration = function _elapsedCycleDuration(animation) {
363    return animation._repeat ? _animationCycle(animation._tTime, animation = animation.duration() + animation._rDelay) * animation : 0;
364  },
365      _animationCycle = function _animationCycle(tTime, cycleDuration) {
366    var whole = Math.floor(tTime /= cycleDuration);
367    return tTime && whole === tTime ? whole - 1 : whole;
368  },
369      _parentToChildTotalTime = function _parentToChildTotalTime(parentTime, child) {
370    return (parentTime - child._start) * child._ts + (child._ts >= 0 ? 0 : child._dirty ? child.totalDuration() : child._tDur);
371  },
372      _setEnd = function _setEnd(animation) {
373    return animation._end = _round(animation._start + (animation._tDur / Math.abs(animation._ts || animation._rts || _tinyNum) || 0));
374  },
375      _alignPlayhead = function _alignPlayhead(animation, totalTime) {
376    var parent = animation._dp;
377
378    if (parent && parent.smoothChildTiming && animation._ts) {
379      animation._start = _round(parent._time - (animation._ts > 0 ? totalTime / animation._ts : ((animation._dirty ? animation.totalDuration() : animation._tDur) - totalTime) / -animation._ts));
380
381      _setEnd(animation);
382
383      parent._dirty || _uncache(parent, animation);
384    }
385
386    return animation;
387  },
388      _postAddChecks = function _postAddChecks(timeline, child) {
389    var t;
390
391    if (child._time || child._initted && !child._dur) {
392      t = _parentToChildTotalTime(timeline.rawTime(), child);
393
394      if (!child._dur || _clamp(0, child.totalDuration(), t) - child._tTime > _tinyNum) {
395        child.render(t, true);
396      }
397    }
398
399    if (_uncache(timeline, child)._dp && timeline._initted && timeline._time >= timeline._dur && timeline._ts) {
400      if (timeline._dur < timeline.duration()) {
401        t = timeline;
402
403        while (t._dp) {
404          t.rawTime() >= 0 && t.totalTime(t._tTime);
405          t = t._dp;
406        }
407      }
408
409      timeline._zTime = -_tinyNum;
410    }
411  },
412      _addToTimeline = function _addToTimeline(timeline, child, position, skipChecks) {
413    child.parent && _removeFromParent(child);
414    child._start = _round(position + child._delay);
415    child._end = _round(child._start + (child.totalDuration() / Math.abs(child.timeScale()) || 0));
416
417    _addLinkedListItem(timeline, child, "_first", "_last", timeline._sort ? "_start" : 0);
418
419    timeline._recent = child;
420    skipChecks || _postAddChecks(timeline, child);
421    return timeline;
422  },
423      _scrollTrigger = function _scrollTrigger(animation, trigger) {
424    return (_globals.ScrollTrigger || _missingPlugin("scrollTrigger", trigger)) && _globals.ScrollTrigger.create(trigger, animation);
425  },
426      _attemptInitTween = function _attemptInitTween(tween, totalTime, force, suppressEvents) {
427    _initTween(tween, totalTime);
428
429    if (!tween._initted) {
430      return 1;
431    }
432
433    if (!force && tween._pt && (tween._dur && tween.vars.lazy !== false || !tween._dur && tween.vars.lazy) && _lastRenderedFrame !== _ticker.frame) {
434      _lazyTweens.push(tween);
435
436      tween._lazy = [totalTime, suppressEvents];
437      return 1;
438    }
439  },
440      _parentPlayheadIsBeforeStart = function _parentPlayheadIsBeforeStart(_ref) {
441    var parent = _ref.parent;
442    return parent && parent._ts && parent._initted && !parent._lock && (parent.rawTime() < 0 || _parentPlayheadIsBeforeStart(parent));
443  },
444      _renderZeroDurationTween = function _renderZeroDurationTween(tween, totalTime, suppressEvents, force) {
445    var prevRatio = tween.ratio,
446        ratio = totalTime < 0 || !totalTime && (!tween._start && _parentPlayheadIsBeforeStart(tween) || (tween._ts < 0 || tween._dp._ts < 0) && tween.data !== "isFromStart" && tween.data !== "isStart") ? 0 : 1,
447        repeatDelay = tween._rDelay,
448        tTime = 0,
449        pt,
450        iteration,
451        prevIteration;
452
453    if (repeatDelay && tween._repeat) {
454      tTime = _clamp(0, tween._tDur, totalTime);
455      iteration = _animationCycle(tTime, repeatDelay);
456      prevIteration = _animationCycle(tween._tTime, repeatDelay);
457      tween._yoyo && iteration & 1 && (ratio = 1 - ratio);
458
459      if (iteration !== prevIteration) {
460        prevRatio = 1 - ratio;
461        tween.vars.repeatRefresh && tween._initted && tween.invalidate();
462      }
463    }
464
465    if (ratio !== prevRatio || force || tween._zTime === _tinyNum || !totalTime && tween._zTime) {
466      if (!tween._initted && _attemptInitTween(tween, totalTime, force, suppressEvents)) {
467        return;
468      }
469
470      prevIteration = tween._zTime;
471      tween._zTime = totalTime || (suppressEvents ? _tinyNum : 0);
472      suppressEvents || (suppressEvents = totalTime && !prevIteration);
473      tween.ratio = ratio;
474      tween._from && (ratio = 1 - ratio);
475      tween._time = 0;
476      tween._tTime = tTime;
477      pt = tween._pt;
478
479      while (pt) {
480        pt.r(ratio, pt.d);
481        pt = pt._next;
482      }
483
484      tween._startAt && totalTime < 0 && tween._startAt.render(totalTime, true, true);
vendor: 9,020 bytes, lines 485-753
485      tween._onUpdate && !suppressEvents && _callback(tween, "onUpdate");
486      tTime && tween._repeat && !suppressEvents && tween.parent && _callback(tween, "onRepeat");
487
488      if ((totalTime >= tween._tDur || totalTime < 0) && tween.ratio === ratio) {
489        ratio && _removeFromParent(tween, 1);
490
491        if (!suppressEvents) {
492          _callback(tween, ratio ? "onComplete" : "onReverseComplete", true);
493
494          tween._prom && tween._prom();
495        }
496      }
497    } else if (!tween._zTime) {
498      tween._zTime = totalTime;
499    }
500  },
501      _findNextPauseTween = function _findNextPauseTween(animation, prevTime, time) {
502    var child;
503
504    if (time > prevTime) {
505      child = animation._first;
506
507      while (child && child._start <= time) {
508        if (!child._dur && child.data === "isPause" && child._start > prevTime) {
509          return child;
510        }
511
512        child = child._next;
513      }
514    } else {
515      child = animation._last;
516
517      while (child && child._start >= time) {
518        if (!child._dur && child.data === "isPause" && child._start < prevTime) {
519          return child;
520        }
521
522        child = child._prev;
523      }
524    }
525  },
526      _setDuration = function _setDuration(animation, duration, skipUncache, leavePlayhead) {
527    var repeat = animation._repeat,
528        dur = _round(duration) || 0,
529        totalProgress = animation._tTime / animation._tDur;
530    totalProgress && !leavePlayhead && (animation._time *= dur / animation._dur);
531    animation._dur = dur;
532    animation._tDur = !repeat ? dur : repeat < 0 ? 1e10 : _round(dur * (repeat + 1) + animation._rDelay * repeat);
533    totalProgress && !leavePlayhead ? _alignPlayhead(animation, animation._tTime = animation._tDur * totalProgress) : animation.parent && _setEnd(animation);
534    skipUncache || _uncache(animation.parent, animation);
535    return animation;
536  },
537      _onUpdateTotalDuration = function _onUpdateTotalDuration(animation) {
538    return animation instanceof Timeline ? _uncache(animation) : _setDuration(animation, animation._dur);
539  },
540      _zeroPosition = {
541    _start: 0,
542    endTime: _emptyFunc
543  },
544      _parsePosition = function _parsePosition(animation, position) {
545    var labels = animation.labels,
546        recent = animation._recent || _zeroPosition,
547        clippedDuration = animation.duration() >= _bigNum ? recent.endTime(false) : animation._dur,
548        i,
549        offset;
550
551    if (_isString(position) && (isNaN(position) || position in labels)) {
552      i = position.charAt(0);
553
554      if (i === "<" || i === ">") {
555        return (i === "<" ? recent._start : recent.endTime(recent._repeat >= 0)) + (parseFloat(position.substr(1)) || 0);
556      }
557
558      i = position.indexOf("=");
559
560      if (i < 0) {
561        position in labels || (labels[position] = clippedDuration);
562        return labels[position];
563      }
564
565      offset = +(position.charAt(i - 1) + position.substr(i + 1));
566      return i > 1 ? _parsePosition(animation, position.substr(0, i - 1)) + offset : clippedDuration + offset;
567    }
568
569    return position == null ? clippedDuration : +position;
570  },
571      _conditionalReturn = function _conditionalReturn(value, func) {
572    return value || value === 0 ? func(value) : func;
573  },
574      _clamp = function _clamp(min, max, value) {
575    return value < min ? min : value > max ? max : value;
576  },
577      getUnit = function getUnit(value) {
578    if (typeof value !== "string") {
579      return "";
580    }
581
582    var v = _unitExp.exec(value);
583
584    return v ? value.substr(v.index + v[0].length) : "";
585  },
586      clamp = function clamp(min, max, value) {
587    return _conditionalReturn(value, function (v) {
588      return _clamp(min, max, v);
589    });
590  },
591      _slice = [].slice,
592      _isArrayLike = function _isArrayLike(value, nonEmpty) {
593    return value && _isObject(value) && "length" in value && (!nonEmpty && !value.length || value.length - 1 in value && _isObject(value[0])) && !value.nodeType && value !== _win;
594  },
595      _flatten = function _flatten(ar, leaveStrings, accumulator) {
596    if (accumulator === void 0) {
597      accumulator = [];
598    }
599
600    return ar.forEach(function (value) {
601      var _accumulator;
602
603      return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value);
604    }) || accumulator;
605  },
606      toArray = function toArray(value, leaveStrings) {
607    return _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call(_doc.querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : [];
608  },
609      shuffle = function shuffle(a) {
610    return a.sort(function () {
611      return .5 - Math.random();
612    });
613  },
614      distribute = function distribute(v) {
615    if (_isFunction(v)) {
616      return v;
617    }
618
619    var vars = _isObject(v) ? v : {
620      each: v
621    },
622        ease = _parseEase(vars.ease),
623        from = vars.from || 0,
624        base = parseFloat(vars.base) || 0,
625        cache = {},
626        isDecimal = from > 0 && from < 1,
627        ratios = isNaN(from) || isDecimal,
628        axis = vars.axis,
629        ratioX = from,
630        ratioY = from;
631
632    if (_isString(from)) {
633      ratioX = ratioY = {
634        center: .5,
635        edges: .5,
636        end: 1
637      }[from] || 0;
638    } else if (!isDecimal && ratios) {
639      ratioX = from[0];
640      ratioY = from[1];
641    }
642
643    return function (i, target, a) {
644      var l = (a || vars).length,
645          distances = cache[l],
646          originX,
647          originY,
648          x,
649          y,
650          d,
651          j,
652          max,
653          min,
654          wrapAt;
655
656      if (!distances) {
657        wrapAt = vars.grid === "auto" ? 0 : (vars.grid || [1, _bigNum])[1];
658
659        if (!wrapAt) {
660          max = -_bigNum;
661
662          while (max < (max = a[wrapAt++].getBoundingClientRect().left) && wrapAt < l) {}
663
664          wrapAt--;
665        }
666
667        distances = cache[l] = [];
668        originX = ratios ? Math.min(wrapAt, l) * ratioX - .5 : from % wrapAt;
669        originY = ratios ? l * ratioY / wrapAt - .5 : from / wrapAt | 0;
670        max = 0;
671        min = _bigNum;
672
673        for (j = 0; j < l; j++) {
674          x = j % wrapAt - originX;
675          y = originY - (j / wrapAt | 0);
676          distances[j] = d = !axis ? _sqrt(x * x + y * y) : Math.abs(axis === "y" ? y : x);
677          d > max && (max = d);
678          d < min && (min = d);
679        }
680
681        from === "random" && shuffle(distances);
682        distances.max = max - min;
683        distances.min = min;
684        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);
685        distances.b = l < 0 ? base - l : base;
686        distances.u = getUnit(vars.amount || vars.each) || 0;
687        ease = ease && l < 0 ? _invertEase(ease) : ease;
688      }
689
690      l = (distances[i] - distances.min) / distances.max || 0;
691      return _round(distances.b + (ease ? ease(l) : l) * distances.v) + distances.u;
692    };
693  },
694      _roundModifier = function _roundModifier(v) {
695    var p = v < 1 ? Math.pow(10, (v + "").length - 2) : 1;
696    return function (raw) {
697      var n = Math.round(parseFloat(raw) / v) * v * p;
698      return (n - n % 1) / p + (_isNumber(raw) ? 0 : getUnit(raw));
699    };
700  },
701      snap = function snap(snapTo, value) {
702    var isArray = _isArray(snapTo),
703        radius,
704        is2D;
705
706    if (!isArray && _isObject(snapTo)) {
707      radius = isArray = snapTo.radius || _bigNum;
708
709      if (snapTo.values) {
710        snapTo = toArray(snapTo.values);
711
712        if (is2D = !_isNumber(snapTo[0])) {
713          radius *= radius;
714        }
715      } else {
716        snapTo = _roundModifier(snapTo.increment);
717      }
718    }
719
720    return _conditionalReturn(value, !isArray ? _roundModifier(snapTo) : _isFunction(snapTo) ? function (raw) {
721      is2D = snapTo(raw);
722      return Math.abs(is2D - raw) <= radius ? is2D : raw;
723    } : function (raw) {
724      var x = parseFloat(is2D ? raw.x : raw),
725          y = parseFloat(is2D ? raw.y : 0),
726          min = _bigNum,
727          closest = 0,
728          i = snapTo.length,
729          dx,
730          dy;
731
732      while (i--) {
733        if (is2D) {
734          dx = snapTo[i].x - x;
735          dy = snapTo[i].y - y;
736          dx = dx * dx + dy * dy;
737        } else {
738          dx = Math.abs(snapTo[i] - x);
739        }
740
741        if (dx < min) {
742          min = dx;
743          closest = i;
744        }
745      }
746
747      closest = !radius || min <= radius ? snapTo[closest] : raw;
748      return is2D || closest === raw || _isNumber(raw) ? closest : closest + getUnit(raw);
749    });
750  },
751      random = function random(min, max, roundingIncrement, returnFunction) {
752    return _conditionalReturn(_isArray(min) ? !max : roundingIncrement === true ? !!(roundingIncrement = 0) : !returnFunction, function () {
753      return _isArray(min) ? min[~~(Math.random() * min.length)] : (roundingIncrement = roundingIncrement || 1e
vendor: 4,723 bytes, lines 753-909
753-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;
754    });
755  },
756      pipe = function pipe() {
757    for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) {
758      functions[_key] = arguments[_key];
759    }
760
761    return function (value) {
762      return functions.reduce(function (v, f) {
763        return f(v);
764      }, value);
765    };
766  },
767      unitize = function unitize(func, unit) {
768    return function (value) {
769      return func(parseFloat(value)) + (unit || getUnit(value));
770    };
771  },
772      normalize = function normalize(min, max, value) {
773    return mapRange(min, max, 0, 1, value);
774  },
775      _wrapArray = function _wrapArray(a, wrapper, value) {
776    return _conditionalReturn(value, function (index) {
777      return a[~~wrapper(index)];
778    });
779  },
780      wrap = function wrap(min, max, value) {
781    var range = max - min;
782    return _isArray(min) ? _wrapArray(min, wrap(0, min.length), max) : _conditionalReturn(value, function (value) {
783      return (range + (value - min) % range) % range + min;
784    });
785  },
786      wrapYoyo = function wrapYoyo(min, max, value) {
787    var range = max - min,
788        total = range * 2;
789    return _isArray(min) ? _wrapArray(min, wrapYoyo(0, min.length - 1), max) : _conditionalReturn(value, function (value) {
790      value = (total + (value - min) % total) % total || 0;
791      return min + (value > range ? total - value : value);
792    });
793  },
794      _replaceRandom = function _replaceRandom(value) {
795    var prev = 0,
796        s = "",
797        i,
798        nums,
799        end,
800        isArray;
801
802    while (~(i = value.indexOf("random(", prev))) {
803      end = value.indexOf(")", i);
804      isArray = value.charAt(i + 7) === "[";
805      nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp);
806      s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5);
807      prev = end + 1;
808    }
809
810    return s + value.substr(prev, value.length - prev);
811  },
812      mapRange = function mapRange(inMin, inMax, outMin, outMax, value) {
813    var inRange = inMax - inMin,
814        outRange = outMax - outMin;
815    return _conditionalReturn(value, function (value) {
816      return outMin + ((value - inMin) / inRange * outRange || 0);
817    });
818  },
819      interpolate = function interpolate(start, end, progress, mutate) {
820    var func = isNaN(start + end) ? 0 : function (p) {
821      return (1 - p) * start + p * end;
822    };
823
824    if (!func) {
825      var isString = _isString(start),
826          master = {},
827          p,
828          i,
829          interpolators,
830          l,
831          il;
832
833      progress === true && (mutate = 1) && (progress = null);
834
835      if (isString) {
836        start = {
837          p: start
838        };
839        end = {
840          p: end
841        };
842      } else if (_isArray(start) && !_isArray(end)) {
843        interpolators = [];
844        l = start.length;
845        il = l - 2;
846
847        for (i = 1; i < l; i++) {
848          interpolators.push(interpolate(start[i - 1], start[i]));
849        }
850
851        l--;
852
853        func = function func(p) {
854          p *= l;
855          var i = Math.min(il, ~~p);
856          return interpolators[i](p - i);
857        };
858
859        progress = end;
860      } else if (!mutate) {
861        start = _merge(_isArray(start) ? [] : {}, start);
862      }
863
864      if (!interpolators) {
865        for (p in end) {
866          _addPropTween.call(master, start, p, "get", end[p]);
867        }
868
869        func = function func(p) {
870          return _renderPropTweens(p, master) || (isString ? start.p : start);
871        };
872      }
873    }
874
875    return _conditionalReturn(progress, func);
876  },
877      _getLabelInDirection = function _getLabelInDirection(timeline, fromTime, backward) {
878    var labels = timeline.labels,
879        min = _bigNum,
880        p,
881        distance,
882        label;
883
884    for (p in labels) {
885      distance = labels[p] - fromTime;
886
887      if (distance < 0 === !!backward && distance && min > (distance = Math.abs(distance))) {
888        label = p;
889        min = distance;
890      }
891    }
892
893    return label;
894  },
895      _callback = function _callback(animation, type, executeLazyFirst) {
896    var v = animation.vars,
897        callback = v[type],
898        params,
899        scope;
900
901    if (!callback) {
902      return;
903    }
904
905    params = v[type + "Params"];
906    scope = v.callbackScope || animation;
907    executeLazyFirst && _lazyTweens.length && _lazyRender();
908    return params ? callback.apply(scope, params) : callback.call(scope);
909  },
vendor: 7,655 bytes, lines 910-1195
910      _interrupt = function _interrupt(animation) {
911    _removeFromParent(animation);
912
913    animation.scrollTrigger && animation.scrollTrigger.kill(false);
914    animation.progress() < 1 && _callback(animation, "onInterrupt");
915    return animation;
916  },
917      _quickTween,
918      _createPlugin = function _createPlugin(config) {
919    config = !config.name && config["default"] || config;
920
921    var name = config.name,
922        isFunc = _isFunction(config),
923        Plugin = name && !isFunc && config.init ? function () {
924      this._props = [];
925    } : config,
926        instanceDefaults = {
927      init: _emptyFunc,
928      render: _renderPropTweens,
929      add: _addPropTween,
930      kill: _killPropTweensOf,
931      modifier: _addPluginModifier,
932      rawVars: 0
933    },
934        statics = {
935      targetTest: 0,
936      get: 0,
937      getSetter: _getSetter,
938      aliases: {},
939      register: 0
940    };
941
942    _wake();
943
944    if (config !== Plugin) {
945      if (_plugins[name]) {
946        return;
947      }
948
949      _setDefaults(Plugin, _setDefaults(_copyExcluding(config, instanceDefaults), statics));
950
951      _merge(Plugin.prototype, _merge(instanceDefaults, _copyExcluding(config, statics)));
952
953      _plugins[Plugin.prop = name] = Plugin;
954
955      if (config.targetTest) {
956        _harnessPlugins.push(Plugin);
957
958        _reservedProps[name] = 1;
959      }
960
961      name = (name === "css" ? "CSS" : name.charAt(0).toUpperCase() + name.substr(1)) + "Plugin";
962    }
963
964    _addGlobal(name, Plugin);
965
966    config.register && config.register(gsap, Plugin, PropTween);
967  },
968      _255 = 255,
969      _colorLookup = {
970    aqua: [0, _255, _255],
971    lime: [0, _255, 0],
972    silver: [192, 192, 192],
973    black: [0, 0, 0],
974    maroon: [128, 0, 0],
975    teal: [0, 128, 128],
976    blue: [0, 0, _255],
977    navy: [0, 0, 128],
978    white: [_255, _255, _255],
979    olive: [128, 128, 0],
980    yellow: [_255, _255, 0],
981    orange: [_255, 165, 0],
982    gray: [128, 128, 128],
983    purple: [128, 0, 128],
984    green: [0, 128, 0],
985    red: [_255, 0, 0],
986    pink: [_255, 192, 203],
987    cyan: [0, _255, _255],
988    transparent: [_255, _255, _255, 0]
989  },
990      _hue = function _hue(h, m1, m2) {
991    h = h < 0 ? h + 1 : h > 1 ? h - 1 : h;
992    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;
993  },
994      splitColor = function splitColor(v, toHSL, forceAlpha) {
995    var a = !v ? _colorLookup.black : _isNumber(v) ? [v >> 16, v >> 8 & _255, v & _255] : 0,
996        r,
997        g,
998        b,
999        h,
1000        s,
1001        l,
1002        max,
1003        min,
1004        d,
1005        wasHSL;
1006
1007    if (!a) {
1008      if (v.substr(-1) === ",") {
1009        v = v.substr(0, v.length - 1);
1010      }
1011
1012      if (_colorLookup[v]) {
1013        a = _colorLookup[v];
1014      } else if (v.charAt(0) === "#") {
1015        if (v.length < 6) {
1016          r = v.charAt(1);
1017          g = v.charAt(2);
1018          b = v.charAt(3);
1019          v = "#" + r + r + g + g + b + b + (v.length === 5 ? v.charAt(4) + v.charAt(4) : "");
1020        }
1021
1022        if (v.length === 9) {
1023          a = parseInt(v.substr(1, 6), 16);
1024          return [a >> 16, a >> 8 & _255, a & _255, parseInt(v.substr(7), 16) / 255];
1025        }
1026
1027        v = parseInt(v.substr(1), 16);
1028        a = [v >> 16, v >> 8 & _255, v & _255];
1029      } else if (v.substr(0, 3) === "hsl") {
1030        a = wasHSL = v.match(_strictNumExp);
1031
1032        if (!toHSL) {
1033          h = +a[0] % 360 / 360;
1034          s = +a[1] / 100;
1035          l = +a[2] / 100;
1036          g = l <= .5 ? l * (s + 1) : l + s - l * s;
1037          r = l * 2 - g;
1038          a.length > 3 && (a[3] *= 1);
1039          a[0] = _hue(h + 1 / 3, r, g);
1040          a[1] = _hue(h, r, g);
1041          a[2] = _hue(h - 1 / 3, r, g);
1042        } else if (~v.indexOf("=")) {
1043          a = v.match(_numExp);
1044          forceAlpha && a.length < 4 && (a[3] = 1);
1045          return a;
1046        }
1047      } else {
1048        a = v.match(_strictNumExp) || _colorLookup.transparent;
1049      }
1050
1051      a = a.map(Number);
1052    }
1053
1054    if (toHSL && !wasHSL) {
1055      r = a[0] / _255;
1056      g = a[1] / _255;
1057      b = a[2] / _255;
1058      max = Math.max(r, g, b);
1059      min = Math.min(r, g, b);
1060      l = (max + min) / 2;
1061
1062      if (max === min) {
1063        h = s = 0;
1064      } else {
1065        d = max - min;
1066        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1067        h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
1068        h *= 60;
1069      }
1070
1071      a[0] = ~~(h + .5);
1072      a[1] = ~~(s * 100 + .5);
1073      a[2] = ~~(l * 100 + .5);
1074    }
1075
1076    forceAlpha && a.length < 4 && (a[3] = 1);
1077    return a;
1078  },
1079      _colorOrderData = function _colorOrderData(v) {
1080    var values = [],
1081        c = [],
1082        i = -1;
1083    v.split(_colorExp).forEach(function (v) {
1084      var a = v.match(_numWithUnitExp) || [];
1085      values.push.apply(values, a);
1086      c.push(i += a.length + 1);
1087    });
1088    values.c = c;
1089    return values;
1090  },
1091      _formatColors = function _formatColors(s, toHSL, orderMatchData) {
1092    var result = "",
1093        colors = (s + result).match(_colorExp),
1094        type = toHSL ? "hsla(" : "rgba(",
1095        i = 0,
1096        c,
1097        shell,
1098        d,
1099        l;
1100
1101    if (!colors) {
1102      return s;
1103    }
1104
1105    colors = colors.map(function (color) {
1106      return (color = splitColor(color, toHSL, 1)) && type + (toHSL ? color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : color.join(",")) + ")";
1107    });
1108
1109    if (orderMatchData) {
1110      d = _colorOrderData(s);
1111      c = orderMatchData.c;
1112
1113      if (c.join(result) !== d.c.join(result)) {
1114        shell = s.replace(_colorExp, "1").split(_numWithUnitExp);
1115        l = shell.length - 1;
1116
1117        for (; i < l; i++) {
1118          result += shell[i] + (~c.indexOf(i) ? colors.shift() || type + "0,0,0,0)" : (d.length ? d : colors.length ? colors : orderMatchData).shift());
1119        }
1120      }
1121    }
1122
1123    if (!shell) {
1124      shell = s.split(_colorExp);
1125      l = shell.length - 1;
1126
1127      for (; i < l; i++) {
1128        result += shell[i] + colors[i];
1129      }
1130    }
1131
1132    return result + shell[l];
1133  },
1134      _colorExp = function () {
1135    var s = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#(?:[0-9a-f]{3,4}){1,2}\\b",
1136        p;
1137
1138    for (p in _colorLookup) {
1139      s += "|" + p + "\\b";
1140    }
1141
1142    return new RegExp(s + ")", "gi");
1143  }(),
1144      _hslExp = /hsl[a]?\(/,
1145      _colorStringFilter = function _colorStringFilter(a) {
1146    var combined = a.join(" "),
1147        toHSL;
1148    _colorExp.lastIndex = 0;
1149
1150    if (_colorExp.test(combined)) {
1151      toHSL = _hslExp.test(combined);
1152      a[1] = _formatColors(a[1], toHSL);
1153      a[0] = _formatColors(a[0], toHSL, _colorOrderData(a[1]));
1154      return true;
1155    }
1156  },
1157      _tickerActive,
1158      _ticker = function () {
1159    var _getTime = Date.now,
1160        _lagThreshold = 500,
1161        _adjustedLag = 33,
1162        _startTime = _getTime(),
1163        _lastUpdate = _startTime,
1164        _gap = 1000 / 240,
1165        _nextTime = _gap,
1166        _listeners = [],
1167        _id,
1168        _req,
1169        _raf,
1170        _self,
1171        _delta,
1172        _i,
1173        _tick = function _tick(v) {
1174      var elapsed = _getTime() - _lastUpdate,
1175          manual = v === true,
1176          overlap,
1177          dispatch,
1178          time,
1179          frame;
1180
1181      elapsed > _lagThreshold && (_startTime += elapsed - _adjustedLag);
1182      _lastUpdate += elapsed;
1183      time = _lastUpdate - _startTime;
1184      overlap = time - _nextTime;
1185
1186      if (overlap > 0 || manual) {
1187        frame = ++_self.frame;
1188        _delta = time - _self.time * 1000;
1189        _self.time = time = time / 1000;
1190        _nextTime += overlap + (overlap >= _gap ? 4 : _gap - overlap);
1191        dispatch = 1;
1192      }
1193
1194      manual || (_id = _req(_tick));
1195
vendor: 4,054 bytes, lines 1196-1323
1196      if (dispatch) {
1197        for (_i = 0; _i < _listeners.length; _i++) {
1198          _listeners[_i](time, _delta, frame, v);
1199        }
1200      }
1201    };
1202
1203    _self = {
1204      time: 0,
1205      frame: 0,
1206      tick: function tick() {
1207        _tick(true);
1208      },
1209      deltaRatio: function deltaRatio(fps) {
1210        return _delta / (1000 / (fps || 60));
1211      },
1212      wake: function wake() {
1213        if (_coreReady) {
1214          if (!_coreInitted && _windowExists()) {
1215            _win = _coreInitted = window;
1216            _doc = _win.document || {};
1217            _globals.gsap = gsap;
1218            (_win.gsapVersions || (_win.gsapVersions = [])).push(gsap.version);
1219
1220            _install(_installScope || _win.GreenSockGlobals || !_win.gsap && _win || {});
1221
1222            _raf = _win.requestAnimationFrame;
1223          }
1224
1225          _id && _self.sleep();
1226
1227          _req = _raf || function (f) {
1228            return setTimeout(f, _nextTime - _self.time * 1000 + 1 | 0);
1229          };
1230
1231          _tickerActive = 1;
1232
1233          _tick(2);
1234        }
1235      },
1236      sleep: function sleep() {
1237        (_raf ? _win.cancelAnimationFrame : clearTimeout)(_id);
1238        _tickerActive = 0;
1239        _req = _emptyFunc;
1240      },
1241      lagSmoothing: function lagSmoothing(threshold, adjustedLag) {
1242        _lagThreshold = threshold || 1 / _tinyNum;
1243        _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0);
1244      },
1245      fps: function fps(_fps) {
1246        _gap = 1000 / (_fps || 240);
1247        _nextTime = _self.time * 1000 + _gap;
1248      },
1249      add: function add(callback) {
1250        _listeners.indexOf(callback) < 0 && _listeners.push(callback);
1251
1252        _wake();
1253      },
1254      remove: function remove(callback) {
1255        var i;
1256        ~(i = _listeners.indexOf(callback)) && _listeners.splice(i, 1) && _i >= i && _i--;
1257      },
1258      _listeners: _listeners
1259    };
1260    return _self;
1261  }(),
1262      _wake = function _wake() {
1263    return !_tickerActive && _ticker.wake();
1264  },
1265      _easeMap = {},
1266      _customEaseExp = /^[\d.\-M][\d.\-,\s]/,
1267      _quotesExp = /["']/g,
1268      _parseObjectInString = function _parseObjectInString(value) {
1269    var obj = {},
1270        split = value.substr(1, value.length - 3).split(":"),
1271        key = split[0],
1272        i = 1,
1273        l = split.length,
1274        index,
1275        val,
1276        parsedVal;
1277
1278    for (; i < l; i++) {
1279      val = split[i];
1280      index = i !== l - 1 ? val.lastIndexOf(",") : val.length;
1281      parsedVal = val.substr(0, index);
1282      obj[key] = isNaN(parsedVal) ? parsedVal.replace(_quotesExp, "").trim() : +parsedVal;
1283      key = val.substr(index + 1).trim();
1284    }
1285
1286    return obj;
1287  },
1288      _valueInParentheses = function _valueInParentheses(value) {
1289    var open = value.indexOf("(") + 1,
1290        close = value.indexOf(")"),
1291        nested = value.indexOf("(", open);
1292    return value.substring(open, ~nested && nested < close ? value.indexOf(")", close + 1) : close);
1293  },
1294      _configEaseFromString = function _configEaseFromString(name) {
1295    var split = (name + "").split("("),
1296        ease = _easeMap[split[0]];
1297    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;
1298  },
1299      _invertEase = function _invertEase(ease) {
1300    return function (p) {
1301      return 1 - ease(1 - p);
1302    };
1303  },
1304      _propagateYoyoEase = function _propagateYoyoEase(timeline, isYoyo) {
1305    var child = timeline._first,
1306        ease;
1307
1308    while (child) {
1309      if (child instanceof Timeline) {
1310        _propagateYoyoEase(child, isYoyo);
1311      } else if (child.vars.yoyoEase && (!child._yoyo || !child._repeat) && child._yoyo !== isYoyo) {
1312        if (child.timeline) {
1313          _propagateYoyoEase(child.timeline, isYoyo);
1314        } else {
1315          ease = child._ease;
1316          child._ease = child._yEase;
1317          child._yEase = ease;
1318          child._yoyo = isYoyo;
1319        }
1320      }
1321
1322      child = child._next;
1323    }
vendor: 3,445 bytes, lines 1323-1434
1323
1324  },
1325      _parseEase = function _parseEase(ease, defaultEase) {
1326    return !ease ? defaultEase : (_isFunction(ease) ? ease : _easeMap[ease] || _configEaseFromString(ease)) || defaultEase;
1327  },
1328      _insertEase = function _insertEase(names, easeIn, easeOut, easeInOut) {
1329    if (easeOut === void 0) {
1330      easeOut = function easeOut(p) {
1331        return 1 - easeIn(1 - p);
1332      };
1333    }
1334
1335    if (easeInOut === void 0) {
1336      easeInOut = function easeInOut(p) {
1337        return p < .5 ? easeIn(p * 2) / 2 : 1 - easeIn((1 - p) * 2) / 2;
1338      };
1339    }
1340
1341    var ease = {
1342      easeIn: easeIn,
1343      easeOut: easeOut,
1344      easeInOut: easeInOut
1345    },
1346        lowercaseName;
1347
1348    _forEachName(names, function (name) {
1349      _easeMap[name] = _globals[name] = ease;
1350      _easeMap[lowercaseName = name.toLowerCase()] = easeOut;
1351
1352      for (var p in ease) {
1353        _easeMap[lowercaseName + (p === "easeIn" ? ".in" : p === "easeOut" ? ".out" : ".inOut")] = _easeMap[name + "." + p] = ease[p];
1354      }
1355    });
1356
1357    return ease;
1358  },
1359      _easeInOutFromOut = function _easeInOutFromOut(easeOut) {
1360    return function (p) {
1361      return p < .5 ? (1 - easeOut(1 - p * 2)) / 2 : .5 + easeOut((p - .5) * 2) / 2;
1362    };
1363  },
1364      _configElastic = function _configElastic(type, amplitude, period) {
1365    var p1 = amplitude >= 1 ? amplitude : 1,
1366        p2 = (period || (type ? .3 : .45)) / (amplitude < 1 ? amplitude : 1),
1367        p3 = p2 / _2PI * (Math.asin(1 / p1) || 0),
1368        easeOut = function easeOut(p) {
1369      return p === 1 ? 1 : p1 * Math.pow(2, -10 * p) * _sin((p - p3) * p2) + 1;
1370    },
1371        ease = type === "out" ? easeOut : type === "in" ? function (p) {
1372      return 1 - easeOut(1 - p);
1373    } : _easeInOutFromOut(easeOut);
1374
1375    p2 = _2PI / p2;
1376
1377    ease.config = function (amplitude, period) {
1378      return _configElastic(type, amplitude, period);
1379    };
1380
1381    return ease;
1382  },
1383      _configBack = function _configBack(type, overshoot) {
1384    if (overshoot === void 0) {
1385      overshoot = 1.70158;
1386    }
1387
1388    var easeOut = function easeOut(p) {
1389      return p ? --p * p * ((overshoot + 1) * p + overshoot) + 1 : 0;
1390    },
1391        ease = type === "out" ? easeOut : type === "in" ? function (p) {
1392      return 1 - easeOut(1 - p);
1393    } : _easeInOutFromOut(easeOut);
1394
1395    ease.config = function (overshoot) {
1396      return _configBack(type, overshoot);
1397    };
1398
1399    return ease;
1400  };
1401
1402  _forEachName("Linear,Quad,Cubic,Quart,Quint,Strong", function (name, i) {
1403    var power = i < 5 ? i + 1 : i;
1404
1405    _insertEase(name + ",Power" + (power - 1), i ? function (p) {
1406      return Math.pow(p, power);
1407    } : function (p) {
1408      return p;
1409    }, function (p) {
1410      return 1 - Math.pow(1 - p, power);
1411    }, function (p) {
1412      return p < .5 ? Math.pow(p * 2, power) / 2 : 1 - Math.pow((1 - p) * 2, power) / 2;
1413    });
1414  });
1415
1416  _easeMap.Linear.easeNone = _easeMap.none = _easeMap.Linear.easeIn;
1417
1418  _insertEase("Elastic", _configElastic("in"), _configElastic("out"), _configElastic());
1419
1420  (function (n, c) {
1421    var n1 = 1 / c,
1422        n2 = 2 * n1,
1423        n3 = 2.5 * n1,
1424        easeOut = function easeOut(p) {
1425      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;
1426    };
1427
1428    _insertEase("Bounce", function (p) {
1429      return 1 - easeOut(1 - p);
1430    }, easeOut);
1431  })(7.5625, 2.75);
1432
1433  _insertEase("Expo", function (p) {
1434    return 
vendor: 6,382 bytes, lines 1434-1617
1434p ? Math.pow(2, 10 * (p - 1)) : 0;
1435  });
1436
1437  _insertEase("Circ", function (p) {
1438    return -(_sqrt(1 - p * p) - 1);
1439  });
1440
1441  _insertEase("Sine", function (p) {
1442    return p === 1 ? 1 : -_cos(p * _HALF_PI) + 1;
1443  });
1444
1445  _insertEase("Back", _configBack("in"), _configBack("out"), _configBack());
1446
1447  _easeMap.SteppedEase = _easeMap.steps = _globals.SteppedEase = {
1448    config: function config(steps, immediateStart) {
1449      if (steps === void 0) {
1450        steps = 1;
1451      }
1452
1453      var p1 = 1 / steps,
1454          p2 = steps + (immediateStart ? 0 : 1),
1455          p3 = immediateStart ? 1 : 0,
1456          max = 1 - _tinyNum;
1457      return function (p) {
1458        return ((p2 * _clamp(0, max, p) | 0) + p3) * p1;
1459      };
1460    }
1461  };
1462  _defaults.ease = _easeMap["quad.out"];
1463
1464  _forEachName("onComplete,onUpdate,onStart,onRepeat,onReverseComplete,onInterrupt", function (name) {
1465    return _callbackNames += name + "," + name + "Params,";
1466  });
1467
1468  var GSCache = function GSCache(target, harness) {
1469    this.id = _gsID++;
1470    target._gsap = this;
1471    this.target = target;
1472    this.harness = harness;
1473    this.get = harness ? harness.get : _getProperty;
1474    this.set = harness ? harness.getSetter : _getSetter;
1475  };
1476  var Animation = function () {
1477    function Animation(vars, time) {
1478      var parent = vars.parent || _globalTimeline;
1479      this.vars = vars;
1480      this._delay = +vars.delay || 0;
1481
1482      if (this._repeat = vars.repeat === Infinity ? -2 : vars.repeat || 0) {
1483        this._rDelay = vars.repeatDelay || 0;
1484        this._yoyo = !!vars.yoyo || !!vars.yoyoEase;
1485      }
1486
1487      this._ts = 1;
1488
1489      _setDuration(this, +vars.duration, 1, 1);
1490
1491      this.data = vars.data;
1492      _tickerActive || _ticker.wake();
1493      parent && _addToTimeline(parent, this, time || time === 0 ? time : parent._time, 1);
1494      vars.reversed && this.reverse();
1495      vars.paused && this.paused(true);
1496    }
1497
1498    var _proto = Animation.prototype;
1499
1500    _proto.delay = function delay(value) {
1501      if (value || value === 0) {
1502        this.parent && this.parent.smoothChildTiming && this.startTime(this._start + value - this._delay);
1503        this._delay = value;
1504        return this;
1505      }
1506
1507      return this._delay;
1508    };
1509
1510    _proto.duration = function duration(value) {
1511      return arguments.length ? this.totalDuration(this._repeat > 0 ? value + (value + this._rDelay) * this._repeat : value) : this.totalDuration() && this._dur;
1512    };
1513
1514    _proto.totalDuration = function totalDuration(value) {
1515      if (!arguments.length) {
1516        return this._tDur;
1517      }
1518
1519      this._dirty = 0;
1520      return _setDuration(this, this._repeat < 0 ? value : (value - this._repeat * this._rDelay) / (this._repeat + 1));
1521    };
1522
1523    _proto.totalTime = function totalTime(_totalTime, suppressEvents) {
1524      _wake();
1525
1526      if (!arguments.length) {
1527        return this._tTime;
1528      }
1529
1530      var parent = this._dp;
1531
1532      if (parent && parent.smoothChildTiming && this._ts) {
1533        _alignPlayhead(this, _totalTime);
1534
1535        !parent._dp || parent.parent || _postAddChecks(parent, this);
1536
1537        while (parent.parent) {
1538          if (parent.parent._time !== parent._start + (parent._ts >= 0 ? parent._tTime / parent._ts : (parent.totalDuration() - parent._tTime) / -parent._ts)) {
1539            parent.totalTime(parent._tTime, true);
1540          }
1541
1542          parent = parent.parent;
1543        }
1544
1545        if (!this.parent && this._dp.autoRemoveChildren && (this._ts > 0 && _totalTime < this._tDur || this._ts < 0 && _totalTime > 0 || !this._tDur && !_totalTime)) {
1546          _addToTimeline(this._dp, this, this._start - this._delay);
1547        }
1548      }
1549
1550      if (this._tTime !== _totalTime || !this._dur && !suppressEvents || this._initted && Math.abs(this._zTime) === _tinyNum || !_totalTime && !this._initted && (this.add || this._ptLookup)) {
1551        this._ts || (this._pTime = _totalTime);
1552
1553        _lazySafeRender(this, _totalTime, suppressEvents);
1554      }
1555
1556      return this;
1557    };
1558
1559    _proto.time = function time(value, suppressEvents) {
1560      return arguments.length ? this.totalTime(Math.min(this.totalDuration(), value + _elapsedCycleDuration(this)) % this._dur || (value ? this._dur : 0), suppressEvents) : this._time;
1561    };
1562
1563    _proto.totalProgress = function totalProgress(value, suppressEvents) {
1564      return arguments.length ? this.totalTime(this.totalDuration() * value, suppressEvents) : this.totalDuration() ? Math.min(1, this._tTime / this._tDur) : this.ratio;
1565    };
1566
1567    _proto.progress = function progress(value, suppressEvents) {
1568      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.ratio;
1569    };
1570
1571    _proto.iteration = function iteration(value, suppressEvents) {
1572      var cycleDuration = this.duration() + this._rDelay;
1573
1574      return arguments.length ? this.totalTime(this._time + (value - 1) * cycleDuration, suppressEvents) : this._repeat ? _animationCycle(this._tTime, cycleDuration) + 1 : 1;
1575    };
1576
1577    _proto.timeScale = function timeScale(value) {
1578      if (!arguments.length) {
1579        return this._rts === -_tinyNum ? 0 : this._rts;
1580      }
1581
1582      if (this._rts === value) {
1583        return this;
1584      }
1585
1586      var tTime = this.parent && this._ts ? _parentToChildTotalTime(this.parent._time, this) : this._tTime;
1587      this._rts = +value || 0;
1588      this._ts = this._ps || value === -_tinyNum ? 0 : this._rts;
1589      return _recacheAncestors(this.totalTime(_clamp(-this._delay, this._tDur, tTime), true));
1590    };
1591
1592    _proto.paused = function paused(value) {
1593      if (!arguments.length) {
1594        return this._ps;
1595      }
1596
1597      if (this._ps !== value) {
1598        this._ps = value;
1599
1600        if (value) {
1601          this._pTime = this._tTime || Math.max(-this._delay, this.rawTime());
1602          this._ts = this._act = 0;
1603        } else {
1604          _wake();
1605
1606          this._ts = this._rts;
1607          this.totalTime(this.parent && !this.parent.smoothChildTiming ? this.rawTime() : this._tTime || this._pTime, this.progress() === 1 && (this._tTime -= _tinyNum) && Math.abs(this._zTime) !== _tinyNum);
1608        }
1609      }
1610
1611      return this;
1612    };
1613
1614    _proto.startTime = function startTime(value) {
1615      if (arguments.length) {
1616        this._start = value;
1617        var parent = this.parent || this._dp;
vendor: 2,817 bytes, lines 1618-1708
1618        parent && (parent._sort || !this.parent) && _addToTimeline(parent, this, value - this._delay);
1619        return this;
1620      }
1621
1622      return this._start;
1623    };
1624
1625    _proto.endTime = function endTime(includeRepeats) {
1626      return this._start + (_isNotFalse(includeRepeats) ? this.totalDuration() : this.duration()) / Math.abs(this._ts);
1627    };
1628
1629    _proto.rawTime = function rawTime(wrapRepeats) {
1630      var parent = this.parent || this._dp;
1631      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);
1632    };
1633
1634    _proto.globalTime = function globalTime(rawTime) {
1635      var animation = this,
1636          time = arguments.length ? rawTime : animation.rawTime();
1637
1638      while (animation) {
1639        time = animation._start + time / (animation._ts || 1);
1640        animation = animation._dp;
1641      }
1642
1643      return time;
1644    };
1645
1646    _proto.repeat = function repeat(value) {
1647      if (arguments.length) {
1648        this._repeat = value === Infinity ? -2 : value;
1649        return _onUpdateTotalDuration(this);
1650      }
1651
1652      return this._repeat === -2 ? Infinity : this._repeat;
1653    };
1654
1655    _proto.repeatDelay = function repeatDelay(value) {
1656      if (arguments.length) {
1657        this._rDelay = value;
1658        return _onUpdateTotalDuration(this);
1659      }
1660
1661      return this._rDelay;
1662    };
1663
1664    _proto.yoyo = function yoyo(value) {
1665      if (arguments.length) {
1666        this._yoyo = value;
1667        return this;
1668      }
1669
1670      return this._yoyo;
1671    };
1672
1673    _proto.seek = function seek(position, suppressEvents) {
1674      return this.totalTime(_parsePosition(this, position), _isNotFalse(suppressEvents));
1675    };
1676
1677    _proto.restart = function restart(includeDelay, suppressEvents) {
1678      return this.play().totalTime(includeDelay ? -this._delay : 0, _isNotFalse(suppressEvents));
1679    };
1680
1681    _proto.play = function play(from, suppressEvents) {
1682      from != null && this.seek(from, suppressEvents);
1683      return this.reversed(false).paused(false);
1684    };
1685
1686    _proto.reverse = function reverse(from, suppressEvents) {
1687      from != null && this.seek(from || this.totalDuration(), suppressEvents);
1688      return this.reversed(true).paused(false);
1689    };
1690
1691    _proto.pause = function pause(atTime, suppressEvents) {
1692      atTime != null && this.seek(atTime, suppressEvents);
1693      return this.paused(true);
1694    };
1695
1696    _proto.resume = function resume() {
1697      return this.paused(false);
1698    };
1699
1700    _proto.reversed = function reversed(value) {
1701      if (arguments.length) {
1702        !!value !== this.reversed() && this.timeScale(-this._rts || (value ? -_tinyNum : 0));
1703        return this;
1704      }
1705
1706      return this._rts < 0;
1707    };
1708
vendor: 8,594 bytes, lines 1709-1972
1709    _proto.invalidate = function invalidate() {
1710      this._initted = this._act = 0;
1711      this._zTime = -_tinyNum;
1712      return this;
1713    };
1714
1715    _proto.isActive = function isActive() {
1716      var parent = this.parent || this._dp,
1717          start = this._start,
1718          rawTime;
1719      return !!(!parent || this._ts && this._initted && parent.isActive() && (rawTime = parent.rawTime(true)) >= start && rawTime < this.endTime(true) - _tinyNum);
1720    };
1721
1722    _proto.eventCallback = function eventCallback(type, callback, params) {
1723      var vars = this.vars;
1724
1725      if (arguments.length > 1) {
1726        if (!callback) {
1727          delete vars[type];
1728        } else {
1729          vars[type] = callback;
1730          params && (vars[type + "Params"] = params);
1731          type === "onUpdate" && (this._onUpdate = callback);
1732        }
1733
1734        return this;
1735      }
1736
1737      return vars[type];
1738    };
1739
1740    _proto.then = function then(onFulfilled) {
1741      var self = this;
1742      return new Promise(function (resolve) {
1743        var f = _isFunction(onFulfilled) ? onFulfilled : _passThrough,
1744            _resolve = function _resolve() {
1745          var _then = self.then;
1746          self.then = null;
1747          _isFunction(f) && (f = f(self)) && (f.then || f === self) && (self.then = _then);
1748          resolve(f);
1749          self.then = _then;
1750        };
1751
1752        if (self._initted && self.totalProgress() === 1 && self._ts >= 0 || !self._tTime && self._ts < 0) {
1753          _resolve();
1754        } else {
1755          self._prom = _resolve;
1756        }
1757      });
1758    };
1759
1760    _proto.kill = function kill() {
1761      _interrupt(this);
1762    };
1763
1764    return Animation;
1765  }();
1766
1767  _setDefaults(Animation.prototype, {
1768    _time: 0,
1769    _start: 0,
1770    _end: 0,
1771    _tTime: 0,
1772    _tDur: 0,
1773    _dirty: 0,
1774    _repeat: 0,
1775    _yoyo: false,
1776    parent: null,
1777    _initted: false,
1778    _rDelay: 0,
1779    _ts: 1,
1780    _dp: 0,
1781    ratio: 0,
1782    _zTime: -_tinyNum,
1783    _prom: 0,
1784    _ps: false,
1785    _rts: 1
1786  });
1787
1788  var Timeline = function (_Animation) {
1789    _inheritsLoose(Timeline, _Animation);
1790
1791    function Timeline(vars, time) {
1792      var _this;
1793
1794      if (vars === void 0) {
1795        vars = {};
1796      }
1797
1798      _this = _Animation.call(this, vars, time) || this;
1799      _this.labels = {};
1800      _this.smoothChildTiming = !!vars.smoothChildTiming;
1801      _this.autoRemoveChildren = !!vars.autoRemoveChildren;
1802      _this._sort = _isNotFalse(vars.sortChildren);
1803      _this.parent && _postAddChecks(_this.parent, _assertThisInitialized(_this));
1804      vars.scrollTrigger && _scrollTrigger(_assertThisInitialized(_this), vars.scrollTrigger);
1805      return _this;
1806    }
1807
1808    var _proto2 = Timeline.prototype;
1809
1810    _proto2.to = function to(targets, vars, position) {
1811      new Tween(targets, _parseVars(arguments, 0, this), _parsePosition(this, _isNumber(vars) ? arguments[3] : position));
1812      return this;
1813    };
1814
1815    _proto2.from = function from(targets, vars, position) {
1816      new Tween(targets, _parseVars(arguments, 1, this), _parsePosition(this, _isNumber(vars) ? arguments[3] : position));
1817      return this;
1818    };
1819
1820    _proto2.fromTo = function fromTo(targets, fromVars, toVars, position) {
1821      new Tween(targets, _parseVars(arguments, 2, this), _parsePosition(this, _isNumber(fromVars) ? arguments[4] : position));
1822      return this;
1823    };
1824
1825    _proto2.set = function set(targets, vars, position) {
1826      vars.duration = 0;
1827      vars.parent = this;
1828      _inheritDefaults(vars).repeatDelay || (vars.repeat = 0);
1829      vars.immediateRender = !!vars.immediateRender;
1830      new Tween(targets, vars, _parsePosition(this, position), 1);
1831      return this;
1832    };
1833
1834    _proto2.call = function call(callback, params, position) {
1835      return _addToTimeline(this, Tween.delayedCall(0, callback, params), _parsePosition(this, position));
1836    };
1837
1838    _proto2.staggerTo = function staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {
1839      vars.duration = duration;
1840      vars.stagger = vars.stagger || stagger;
1841      vars.onComplete = onCompleteAll;
1842      vars.onCompleteParams = onCompleteAllParams;
1843      vars.parent = this;
1844      new Tween(targets, vars, _parsePosition(this, position));
1845      return this;
1846    };
1847
1848    _proto2.staggerFrom = function staggerFrom(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams) {
1849      vars.runBackwards = 1;
1850      _inheritDefaults(vars).immediateRender = _isNotFalse(vars.immediateRender);
1851      return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams);
1852    };
1853
1854    _proto2.staggerFromTo = function staggerFromTo(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams) {
1855      toVars.startAt = fromVars;
1856      _inheritDefaults(toVars).immediateRender = _isNotFalse(toVars.immediateRender);
1857      return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams);
1858    };
1859
1860    _proto2.render = function render(totalTime, suppressEvents, force) {
1861      var prevTime = this._time,
1862          tDur = this._dirty ? this.totalDuration() : this._tDur,
1863          dur = this._dur,
1864          tTime = this !== _globalTimeline && totalTime > tDur - _tinyNum && totalTime >= 0 ? tDur : totalTime < _tinyNum ? 0 : totalTime,
1865          crossingStart = this._zTime < 0 !== totalTime < 0 && (this._initted || !dur),
1866          time,
1867          child,
1868          next,
1869          iteration,
1870          cycleDuration,
1871          prevPaused,
1872          pauseTween,
1873          timeScale,
1874          prevStart,
1875          prevIteration,
1876          yoyo,
1877          isYoyo;
1878
1879      if (tTime !== this._tTime || force || crossingStart) {
1880        if (prevTime !== this._time && dur) {
1881          tTime += this._time - prevTime;
1882          totalTime += this._time - prevTime;
1883        }
1884
1885        time = tTime;
1886        prevStart = this._start;
1887        timeScale = this._ts;
1888        prevPaused = !timeScale;
1889
1890        if (crossingStart) {
1891          dur || (prevTime = this._zTime);
1892          (totalTime || !suppressEvents) && (this._zTime = totalTime);
1893        }
1894
1895        if (this._repeat) {
1896          yoyo = this._yoyo;
1897          cycleDuration = dur + this._rDelay;
1898
1899          if (this._repeat < -1 && totalTime < 0) {
1900            return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);
1901          }
1902
1903          time = _round(tTime % cycleDuration);
1904
1905          if (tTime === tDur) {
1906            iteration = this._repeat;
1907            time = dur;
1908          } else {
1909            iteration = ~~(tTime / cycleDuration);
1910
1911            if (iteration && iteration === tTime / cycleDuration) {
1912              time = dur;
1913              iteration--;
1914            }
1915
1916            time > dur && (time = dur);
1917          }
1918
1919          prevIteration = _animationCycle(this._tTime, cycleDuration);
1920          !prevTime && this._tTime && prevIteration !== iteration && (prevIteration = iteration);
1921
1922          if (yoyo && iteration & 1) {
1923            time = dur - time;
1924            isYoyo = 1;
1925          }
1926
1927          if (iteration !== prevIteration && !this._lock) {
1928            var rewinding = yoyo && prevIteration & 1,
1929                doesWrap = rewinding === (yoyo && iteration & 1);
1930            iteration < prevIteration && (rewinding = !rewinding);
1931            prevTime = rewinding ? 0 : dur;
1932            this._lock = 1;
1933            this.render(prevTime || (isYoyo ? 0 : _round(iteration * cycleDuration)), suppressEvents, !dur)._lock = 0;
1934            !suppressEvents && this.parent && _callback(this, "onRepeat");
1935            this.vars.repeatRefresh && !isYoyo && (this.invalidate()._lock = 1);
1936
1937            if (prevTime && prevTime !== this._time || prevPaused !== !this._ts || this.vars.onRepeat && !this.parent && !this._act) {
1938              return this;
1939            }
1940
1941            dur = this._dur;
1942            tDur = this._tDur;
1943
1944            if (doesWrap) {
1945              this._lock = 2;
1946              prevTime = rewinding ? dur : -0.0001;
1947              this.render(prevTime, true);
1948            }
1949
1950            this._lock = 0;
1951
1952            if (!this._ts && !prevPaused) {
1953              return this;
1954            }
1955
1956            _propagateYoyoEase(this, isYoyo);
1957          }
1958        }
1959
1960        if (this._hasPause && !this._forcing && this._lock < 2) {
1961          pauseTween = _findNextPauseTween(this, _round(prevTime), _round(time));
1962
1963          if (pauseTween) {
1964            tTime -= time - (time = pauseTween._start);
1965          }
1966        }
1967
1968        this._tTime = tTime;
1969        this._time = time;
1970        this._act = !timeScale;
1971
1972        if (!this._initted) {
vendor: 14,850 bytes, lines 1973-2493
1973          this._onUpdate = this.vars.onUpdate;
1974          this._initted = 1;
1975          this._zTime = totalTime;
1976          prevTime = 0;
1977        }
1978
1979        !prevTime && time && !suppressEvents && _callback(this, "onStart");
1980
1981        if (time >= prevTime && totalTime >= 0) {
1982          child = this._first;
1983
1984          while (child) {
1985            next = child._next;
1986
1987            if ((child._act || time >= child._start) && child._ts && pauseTween !== child) {
1988              if (child.parent !== this) {
1989                return this.render(totalTime, suppressEvents, force);
1990              }
1991
1992              child.render(child._ts > 0 ? (time - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (time - child._start) * child._ts, suppressEvents, force);
1993
1994              if (time !== this._time || !this._ts && !prevPaused) {
1995                pauseTween = 0;
1996                next && (tTime += this._zTime = -_tinyNum);
1997                break;
1998              }
1999            }
2000
2001            child = next;
2002          }
2003        } else {
2004          child = this._last;
2005          var adjustedTime = totalTime < 0 ? totalTime : time;
2006
2007          while (child) {
2008            next = child._prev;
2009
2010            if ((child._act || adjustedTime <= child._end) && child._ts && pauseTween !== child) {
2011              if (child.parent !== this) {
2012                return this.render(totalTime, suppressEvents, force);
2013              }
2014
2015              child.render(child._ts > 0 ? (adjustedTime - child._start) * child._ts : (child._dirty ? child.totalDuration() : child._tDur) + (adjustedTime - child._start) * child._ts, suppressEvents, force);
2016
2017              if (time !== this._time || !this._ts && !prevPaused) {
2018                pauseTween = 0;
2019                next && (tTime += this._zTime = adjustedTime ? -_tinyNum : _tinyNum);
2020                break;
2021              }
2022            }
2023
2024            child = next;
2025          }
2026        }
2027
2028        if (pauseTween && !suppressEvents) {
2029          this.pause();
2030          pauseTween.render(time >= prevTime ? 0 : -_tinyNum)._zTime = time >= prevTime ? 1 : -1;
2031
2032          if (this._ts) {
2033            this._start = prevStart;
2034
2035            _setEnd(this);
2036
2037            return this.render(totalTime, suppressEvents, force);
2038          }
2039        }
2040
2041        this._onUpdate && !suppressEvents && _callback(this, "onUpdate", true);
2042        if (tTime === tDur && tDur >= this.totalDuration() || !tTime && prevTime) if (prevStart === this._start || Math.abs(timeScale) !== Math.abs(this._ts)) if (!this._lock) {
2043          (totalTime || !dur) && (tTime === tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1);
2044
2045          if (!suppressEvents && !(totalTime < 0 && !prevTime) && (tTime || prevTime)) {
2046            _callback(this, tTime === tDur ? "onComplete" : "onReverseComplete", true);
2047
2048            this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();
2049          }
2050        }
2051      }
2052
2053      return this;
2054    };
2055
2056    _proto2.add = function add(child, position) {
2057      var _this2 = this;
2058
2059      _isNumber(position) || (position = _parsePosition(this, position));
2060
2061      if (!(child instanceof Animation)) {
2062        if (_isArray(child)) {
2063          child.forEach(function (obj) {
2064            return _this2.add(obj, position);
2065          });
2066          return this;
2067        }
2068
2069        if (_isString(child)) {
2070          return this.addLabel(child, position);
2071        }
2072
2073        if (_isFunction(child)) {
2074          child = Tween.delayedCall(0, child);
2075        } else {
2076          return this;
2077        }
2078      }
2079
2080      return this !== child ? _addToTimeline(this, child, position) : this;
2081    };
2082
2083    _proto2.getChildren = function getChildren(nested, tweens, timelines, ignoreBeforeTime) {
2084      if (nested === void 0) {
2085        nested = true;
2086      }
2087
2088      if (tweens === void 0) {
2089        tweens = true;
2090      }
2091
2092      if (timelines === void 0) {
2093        timelines = true;
2094      }
2095
2096      if (ignoreBeforeTime === void 0) {
2097        ignoreBeforeTime = -_bigNum;
2098      }
2099
2100      var a = [],
2101          child = this._first;
2102
2103      while (child) {
2104        if (child._start >= ignoreBeforeTime) {
2105          if (child instanceof Tween) {
2106            tweens && a.push(child);
2107          } else {
2108            timelines && a.push(child);
2109            nested && a.push.apply(a, child.getChildren(true, tweens, timelines));
2110          }
2111        }
2112
2113        child = child._next;
2114      }
2115
2116      return a;
2117    };
2118
2119    _proto2.getById = function getById(id) {
2120      var animations = this.getChildren(1, 1, 1),
2121          i = animations.length;
2122
2123      while (i--) {
2124        if (animations[i].vars.id === id) {
2125          return animations[i];
2126        }
2127      }
2128    };
2129
2130    _proto2.remove = function remove(child) {
2131      if (_isString(child)) {
2132        return this.removeLabel(child);
2133      }
2134
2135      if (_isFunction(child)) {
2136        return this.killTweensOf(child);
2137      }
2138
2139      _removeLinkedListItem(this, child);
2140
2141      if (child === this._recent) {
2142        this._recent = this._last;
2143      }
2144
2145      return _uncache(this);
2146    };
2147
2148    _proto2.totalTime = function totalTime(_totalTime2, suppressEvents) {
2149      if (!arguments.length) {
2150        return this._tTime;
2151      }
2152
2153      this._forcing = 1;
2154
2155      if (!this._dp && this._ts) {
2156        this._start = _round(_ticker.time - (this._ts > 0 ? _totalTime2 / this._ts : (this.totalDuration() - _totalTime2) / -this._ts));
2157      }
2158
2159      _Animation.prototype.totalTime.call(this, _totalTime2, suppressEvents);
2160
2161      this._forcing = 0;
2162      return this;
2163    };
2164
2165    _proto2.addLabel = function addLabel(label, position) {
2166      this.labels[label] = _parsePosition(this, position);
2167      return this;
2168    };
2169
2170    _proto2.removeLabel = function removeLabel(label) {
2171      delete this.labels[label];
2172      return this;
2173    };
2174
2175    _proto2.addPause = function addPause(position, callback, params) {
2176      var t = Tween.delayedCall(0, callback || _emptyFunc, params);
2177      t.data = "isPause";
2178      this._hasPause = 1;
2179      return _addToTimeline(this, t, _parsePosition(this, position));
2180    };
2181
2182    _proto2.removePause = function removePause(position) {
2183      var child = this._first;
2184      position = _parsePosition(this, position);
2185
2186      while (child) {
2187        if (child._start === position && child.data === "isPause") {
2188          _removeFromParent(child);
2189        }
2190
2191        child = child._next;
2192      }
2193    };
2194
2195    _proto2.killTweensOf = function killTweensOf(targets, props, onlyActive) {
2196      var tweens = this.getTweensOf(targets, onlyActive),
2197          i = tweens.length;
2198
2199      while (i--) {
2200        _overwritingTween !== tweens[i] && tweens[i].kill(targets, props);
2201      }
2202
2203      return this;
2204    };
2205
2206    _proto2.getTweensOf = function getTweensOf(targets, onlyActive) {
2207      var a = [],
2208          parsedTargets = toArray(targets),
2209          child = this._first,
2210          isGlobalTime = _isNumber(onlyActive),
2211          children;
2212
2213      while (child) {
2214        if (child instanceof Tween) {
2215          if (_arrayContainsAny(child._targets, parsedTargets) && (isGlobalTime ? (!_overwritingTween || child._initted && child._ts) && child.globalTime(0) <= onlyActive && child.globalTime(child.totalDuration()) > onlyActive : !onlyActive || child.isActive())) {
2216            a.push(child);
2217          }
2218        } else if ((children = child.getTweensOf(parsedTargets, onlyActive)).length) {
2219          a.push.apply(a, children);
2220        }
2221
2222        child = child._next;
2223      }
2224
2225      return a;
2226    };
2227
2228    _proto2.tweenTo = function tweenTo(position, vars) {
2229      vars = vars || {};
2230
2231      var tl = this,
2232          endTime = _parsePosition(tl, position),
2233          _vars = vars,
2234          startAt = _vars.startAt,
2235          _onStart = _vars.onStart,
2236          onStartParams = _vars.onStartParams,
2237          immediateRender = _vars.immediateRender,
2238          tween = Tween.to(tl, _setDefaults({
2239        ease: vars.ease || "none",
2240        lazy: false,
2241        immediateRender: false,
2242        time: endTime,
2243        overwrite: "auto",
2244        duration: vars.duration || Math.abs((endTime - (startAt && "time" in startAt ? startAt.time : tl._time)) / tl.timeScale()) || _tinyNum,
2245        onStart: function onStart() {
2246          tl.pause();
2247          var duration = vars.duration || Math.abs((endTime - tl._time) / tl.timeScale());
2248          tween._dur !== duration && _setDuration(tween, duration, 0, 1).render(tween._time, true, true);
2249          _onStart && _onStart.apply(tween, onStartParams || []);
2250        }
2251      }, vars));
2252
2253      return immediateRender ? tween.render(0) : tween;
2254    };
2255
2256    _proto2.tweenFromTo = function tweenFromTo(fromPosition, toPosition, vars) {
2257      return this.tweenTo(toPosition, _setDefaults({
2258        startAt: {
2259          time: _parsePosition(this, fromPosition)
2260        }
2261      }, vars));
2262    };
2263
2264    _proto2.recent = function recent() {
2265      return this._recent;
2266    };
2267
2268    _proto2.nextLabel = function nextLabel(afterTime) {
2269      if (afterTime === void 0) {
2270        afterTime = this._time;
2271      }
2272
2273      return _getLabelInDirection(this, _parsePosition(this, afterTime));
2274    };
2275
2276    _proto2.previousLabel = function previousLabel(beforeTime) {
2277      if (beforeTime === void 0) {
2278        beforeTime = this._time;
2279      }
2280
2281      return _getLabelInDirection(this, _parsePosition(this, beforeTime), 1);
2282    };
2283
2284    _proto2.currentLabel = function currentLabel(value) {
2285      return arguments.length ? this.seek(value, true) : this.previousLabel(this._time + _tinyNum);
2286    };
2287
2288    _proto2.shiftChildren = function shiftChildren(amount, adjustLabels, ignoreBeforeTime) {
2289      if (ignoreBeforeTime === void 0) {
2290        ignoreBeforeTime = 0;
2291      }
2292
2293      var child = this._first,
2294          labels = this.labels,
2295          p;
2296
2297      while (child) {
2298        if (child._start >= ignoreBeforeTime) {
2299          child._start += amount;
2300          child._end += amount;
2301        }
2302
2303        child = child._next;
2304      }
2305
2306      if (adjustLabels) {
2307        for (p in labels) {
2308          if (labels[p] >= ignoreBeforeTime) {
2309            labels[p] += amount;
2310          }
2311        }
2312      }
2313
2314      return _uncache(this);
2315    };
2316
2317    _proto2.invalidate = function invalidate() {
2318      var child = this._first;
2319      this._lock = 0;
2320
2321      while (child) {
2322        child.invalidate();
2323        child = child._next;
2324      }
2325
2326      return _Animation.prototype.invalidate.call(this);
2327    };
2328
2329    _proto2.clear = function clear(includeLabels) {
2330      if (includeLabels === void 0) {
2331        includeLabels = true;
2332      }
2333
2334      var child = this._first,
2335          next;
2336
2337      while (child) {
2338        next = child._next;
2339        this.remove(child);
2340        child = next;
2341      }
2342
2343      this._dp && (this._time = this._tTime = this._pTime = 0);
2344      includeLabels && (this.labels = {});
2345      return _uncache(this);
2346    };
2347
2348    _proto2.totalDuration = function totalDuration(value) {
2349      var max = 0,
2350          self = this,
2351          child = self._last,
2352          prevStart = _bigNum,
2353          prev,
2354          start,
2355          parent;
2356
2357      if (arguments.length) {
2358        return self.timeScale((self._repeat < 0 ? self.duration() : self.totalDuration()) / (self.reversed() ? -value : value));
2359      }
2360
2361      if (self._dirty) {
2362        parent = self.parent;
2363
2364        while (child) {
2365          prev = child._prev;
2366          child._dirty && child.totalDuration();
2367          start = child._start;
2368
2369          if (start > prevStart && self._sort && child._ts && !self._lock) {
2370            self._lock = 1;
2371            _addToTimeline(self, child, start - child._delay, 1)._lock = 0;
2372          } else {
2373            prevStart = start;
2374          }
2375
2376          if (start < 0 && child._ts) {
2377            max -= start;
2378
2379            if (!parent && !self._dp || parent && parent.smoothChildTiming) {
2380              self._start += start / self._ts;
2381              self._time -= start;
2382              self._tTime -= start;
2383            }
2384
2385            self.shiftChildren(-start, false, -1e999);
2386            prevStart = 0;
2387          }
2388
2389          child._end > max && child._ts && (max = child._end);
2390          child = prev;
2391        }
2392
2393        _setDuration(self, self === _globalTimeline && self._time > max ? self._time : max, 1, 1);
2394
2395        self._dirty = 0;
2396      }
2397
2398      return self._tDur;
2399    };
2400
2401    Timeline.updateRoot = function updateRoot(time) {
2402      if (_globalTimeline._ts) {
2403        _lazySafeRender(_globalTimeline, _parentToChildTotalTime(time, _globalTimeline));
2404
2405        _lastRenderedFrame = _ticker.frame;
2406      }
2407
2408      if (_ticker.frame >= _nextGCFrame) {
2409        _nextGCFrame += _config.autoSleep || 120;
2410        var child = _globalTimeline._first;
2411        if (!child || !child._ts) if (_config.autoSleep && _ticker._listeners.length < 2) {
2412          while (child && !child._ts) {
2413            child = child._next;
2414          }
2415
2416          child || _ticker.sleep();
2417        }
2418      }
2419    };
2420
2421    return Timeline;
2422  }(Animation);
2423
2424  _setDefaults(Timeline.prototype, {
2425    _lock: 0,
2426    _hasPause: 0,
2427    _forcing: 0
2428  });
2429
2430  var _addComplexStringPropTween = function _addComplexStringPropTween(target, prop, start, end, setter, stringFilter, funcParam) {
2431    var pt = new PropTween(this._pt, target, prop, 0, 1, _renderComplexString, null, setter),
2432        index = 0,
2433        matchIndex = 0,
2434        result,
2435        startNums,
2436        color,
2437        endNum,
2438        chunk,
2439        startNum,
2440        hasRandom,
2441        a;
2442    pt.b = start;
2443    pt.e = end;
2444    start += "";
2445    end += "";
2446
2447    if (hasRandom = ~end.indexOf("random(")) {
2448      end = _replaceRandom(end);
2449    }
2450
2451    if (stringFilter) {
2452      a = [start, end];
2453      stringFilter(a, target, prop);
2454      start = a[0];
2455      end = a[1];
2456    }
2457
2458    startNums = start.match(_complexStringNumExp) || [];
2459
2460    while (result = _complexStringNumExp.exec(end)) {
2461      endNum = result[0];
2462      chunk = end.substring(index, result.index);
2463
2464      if (color) {
2465        color = (color + 1) % 5;
2466      } else if (chunk.substr(-5) === "rgba(") {
2467        color = 1;
2468      }
2469
2470      if (endNum !== startNums[matchIndex++]) {
2471        startNum = parseFloat(startNums[matchIndex - 1]) || 0;
2472        pt._pt = {
2473          _next: pt._pt,
2474          p: chunk || matchIndex === 1 ? chunk : ",",
2475          s: startNum,
2476          c: endNum.charAt(1) === "=" ? parseFloat(endNum.substr(2)) * (endNum.charAt(0) === "-" ? -1 : 1) : parseFloat(endNum) - startNum,
2477          m: color && color < 4 ? Math.round : 0
2478        };
2479        index = _complexStringNumExp.lastIndex;
2480      }
2481    }
2482
2483    pt.c = index < end.length ? end.substring(index, end.length) : "";
2484    pt.fp = funcParam;
2485
2486    if (_relExp.test(end) || hasRandom) {
2487      pt.e = 0;
2488    }
2489
2490    this._pt = pt;
2491    return pt;
2492  },
2493      _addPropTween = function _addPropTween(target, prop, start, end, index, targets, modifier, stringFilter, funcParam) {
vendor: 7,950 bytes, lines 2494-2719
2494    _isFunction(end) && (end = end(index || 0, target, targets));
2495    var currentValue = target[prop],
2496        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](),
2497        setter = !_isFunction(currentValue) ? _setterPlain : funcParam ? _setterFuncWithParam : _setterFunc,
2498        pt;
2499
2500    if (_isString(end)) {
2501      if (~end.indexOf("random(")) {
2502        end = _replaceRandom(end);
2503      }
2504
2505      if (end.charAt(1) === "=") {
2506        end = parseFloat(parsedStart) + parseFloat(end.substr(2)) * (end.charAt(0) === "-" ? -1 : 1) + (getUnit(parsedStart) || 0);
2507      }
2508    }
2509
2510    if (parsedStart !== end) {
2511      if (!isNaN(parsedStart * end)) {
2512        pt = new PropTween(this._pt, target, prop, +parsedStart || 0, end - (parsedStart || 0), typeof currentValue === "boolean" ? _renderBoolean : _renderPlain, 0, setter);
2513        funcParam && (pt.fp = funcParam);
2514        modifier && pt.modifier(modifier, this, target);
2515        return this._pt = pt;
2516      }
2517
2518      !currentValue && !(prop in target) && _missingPlugin(prop, end);
2519      return _addComplexStringPropTween.call(this, target, prop, parsedStart, end, setter, stringFilter || _config.stringFilter, funcParam);
2520    }
2521  },
2522      _processVars = function _processVars(vars, index, target, targets, tween) {
2523    _isFunction(vars) && (vars = _parseFuncOrString(vars, tween, index, target, targets));
2524
2525    if (!_isObject(vars) || vars.style && vars.nodeType || _isArray(vars) || _isTypedArray(vars)) {
2526      return _isString(vars) ? _parseFuncOrString(vars, tween, index, target, targets) : vars;
2527    }
2528
2529    var copy = {},
2530        p;
2531
2532    for (p in vars) {
2533      copy[p] = _parseFuncOrString(vars[p], tween, index, target, targets);
2534    }
2535
2536    return copy;
2537  },
2538      _checkPlugin = function _checkPlugin(property, vars, tween, index, target, targets) {
2539    var plugin, pt, ptLookup, i;
2540
2541    if (_plugins[property] && (plugin = new _plugins[property]()).init(target, plugin.rawVars ? vars[property] : _processVars(vars[property], index, target, targets, tween), tween, index, targets) !== false) {
2542      tween._pt = pt = new PropTween(tween._pt, target, property, 0, 1, plugin.render, plugin, 0, plugin.priority);
2543
2544      if (tween !== _quickTween) {
2545        ptLookup = tween._ptLookup[tween._targets.indexOf(target)];
2546        i = plugin._props.length;
2547
2548        while (i--) {
2549          ptLookup[plugin._props[i]] = pt;
2550        }
2551      }
2552    }
2553
2554    return plugin;
2555  },
2556      _overwritingTween,
2557      _initTween = function _initTween(tween, time) {
2558    var vars = tween.vars,
2559        ease = vars.ease,
2560        startAt = vars.startAt,
2561        immediateRender = vars.immediateRender,
2562        lazy = vars.lazy,
2563        onUpdate = vars.onUpdate,
2564        onUpdateParams = vars.onUpdateParams,
2565        callbackScope = vars.callbackScope,
2566        runBackwards = vars.runBackwards,
2567        yoyoEase = vars.yoyoEase,
2568        keyframes = vars.keyframes,
2569        autoRevert = vars.autoRevert,
2570        dur = tween._dur,
2571        prevStartAt = tween._startAt,
2572        targets = tween._targets,
2573        parent = tween.parent,
2574        fullTargets = parent && parent.data === "nested" ? parent.parent._targets : targets,
2575        autoOverwrite = tween._overwrite === "auto" && !_suppressOverwrites,
2576        tl = tween.timeline,
2577        cleanVars,
2578        i,
2579        p,
2580        pt,
2581        target,
2582        hasPriority,
2583        gsData,
2584        harness,
2585        plugin,
2586        ptLookup,
2587        index,
2588        harnessVars,
2589        overwritten;
2590    tl && (!keyframes || !ease) && (ease = "none");
2591    tween._ease = _parseEase(ease, _defaults.ease);
2592    tween._yEase = yoyoEase ? _invertEase(_parseEase(yoyoEase === true ? ease : yoyoEase, _defaults.ease)) : 0;
2593
2594    if (yoyoEase && tween._yoyo && !tween._repeat) {
2595      yoyoEase = tween._yEase;
2596      tween._yEase = tween._ease;
2597      tween._ease = yoyoEase;
2598    }
2599
2600    if (!tl) {
2601      harness = targets[0] ? _getCache(targets[0]).harness : 0;
2602      harnessVars = harness && vars[harness.prop];
2603      cleanVars = _copyExcluding(vars, _reservedProps);
2604      prevStartAt && prevStartAt.render(-1, true).kill();
2605
2606      if (startAt) {
2607        _removeFromParent(tween._startAt = Tween.set(targets, _setDefaults({
2608          data: "isStart",
2609          overwrite: false,
2610          parent: parent,
2611          immediateRender: true,
2612          lazy: _isNotFalse(lazy),
2613          startAt: null,
2614          delay: 0,
2615          onUpdate: onUpdate,
2616          onUpdateParams: onUpdateParams,
2617          callbackScope: callbackScope,
2618          stagger: 0
2619        }, startAt)));
2620
2621        if (immediateRender) {
2622          if (time > 0) {
2623            autoRevert || (tween._startAt = 0);
2624          } else if (dur && !(time < 0 && prevStartAt)) {
2625            time && (tween._zTime = time);
2626            return;
2627          }
2628        } else if (autoRevert === false) {
2629          tween._startAt = 0;
2630        }
2631      } else if (runBackwards && dur) {
2632        if (prevStartAt) {
2633          !autoRevert && (tween._startAt = 0);
2634        } else {
2635          time && (immediateRender = false);
2636          p = _setDefaults({
2637            overwrite: false,
2638            data: "isFromStart",
2639            lazy: immediateRender && _isNotFalse(lazy),
2640            immediateRender: immediateRender,
2641            stagger: 0,
2642            parent: parent
2643          }, cleanVars);
2644          harnessVars && (p[harness.prop] = harnessVars);
2645
2646          _removeFromParent(tween._startAt = Tween.set(targets, p));
2647
2648          if (!immediateRender) {
2649            _initTween(tween._startAt, _tinyNum);
2650          } else if (!time) {
2651            return;
2652          }
2653        }
2654      }
2655
2656      tween._pt = 0;
2657      lazy = dur && _isNotFalse(lazy) || lazy && !dur;
2658
2659      for (i = 0; i < targets.length; i++) {
2660        target = targets[i];
2661        gsData = target._gsap || _harness(targets)[i]._gsap;
2662        tween._ptLookup[i] = ptLookup = {};
2663        _lazyLookup[gsData.id] && _lazyTweens.length && _lazyRender();
2664        index = fullTargets === targets ? i : fullTargets.indexOf(target);
2665
2666        if (harness && (plugin = new harness()).init(target, harnessVars || cleanVars, tween, index, fullTargets) !== false) {
2667          tween._pt = pt = new PropTween(tween._pt, target, plugin.name, 0, 1, plugin.render, plugin, 0, plugin.priority);
2668
2669          plugin._props.forEach(function (name) {
2670            ptLookup[name] = pt;
2671          });
2672
2673          plugin.priority && (hasPriority = 1);
2674        }
2675
2676        if (!harness || harnessVars) {
2677          for (p in cleanVars) {
2678            if (_plugins[p] && (plugin = _checkPlugin(p, cleanVars, tween, index, target, fullTargets))) {
2679              plugin.priority && (hasPriority = 1);
2680            } else {
2681              ptLookup[p] = pt = _addPropTween.call(tween, target, p, "get", cleanVars[p], index, fullTargets, 0, vars.stringFilter);
2682            }
2683          }
2684        }
2685
2686        tween._op && tween._op[i] && tween.kill(target, tween._op[i]);
2687
2688        if (autoOverwrite && tween._pt) {
2689          _overwritingTween = tween;
2690
2691          _globalTimeline.killTweensOf(target, ptLookup, tween.globalTime(0));
2692
2693          overwritten = !tween.parent;
2694          _overwritingTween = 0;
2695        }
2696
2697        tween._pt && lazy && (_lazyLookup[gsData.id] = 1);
2698      }
2699
2700      hasPriority && _sortPropTweensByPriority(tween);
2701      tween._onInit && tween._onInit(tween);
2702    }
2703
2704    tween._from = !tl && !!vars.runBackwards;
2705    tween._onUpdate = onUpdate;
2706    tween._initted = (!tween._op || tween._pt) && !overwritten;
2707  },
2708      _addAliasesToVars = function _addAliasesToVars(targets, vars) {
2709    var harness = targets[0] ? _getCache(targets[0]).harness : 0,
2710        propertyAliases = harness && harness.aliases,
2711        copy,
2712        p,
2713        i,
2714        aliases;
2715
2716    if (!propertyAliases) {
2717      return vars;
2718    }
2719
2720    copy = _merge({}, vars);
2721
2722    for (p in propertyAliases) {
2723      if (p in copy) {
2724        aliases = propertyAliases[p].split(",");
2725        i = aliases.length;
2726
2727        while (i--) {
2728          copy[aliases[i]] = copy[p];
2729        }
2730      }
2731    }
2732
2733    return copy;
2734  },
2735      _parseFuncOrString = function _parseFuncOrString(value, tween, i, target, targets) {
2736    return _isFunction(value) ? value.call(tween, i, target, targets) : _isString(value) && ~value.indexOf("random(") ? _replaceRandom(value) : value;
2737  },
2738      _staggerTweenProps = _callbackNames + "repeat,repeatDelay,yoyo,repeatRefresh,yoyoEase",
2739      _staggerPropsToSkip = (_staggerTweenProps + ",id,stagger,delay,duration,paused,scrollTrigger").split(",");
2740
2741  var Tween = function (_Animation2) {
2742    _inheritsLoose(Tween, _Animation2);
2743
2744    function Tween(targets, vars, time, skipInherit) {
2745      var _this3;
2746
2747      if (typeof vars === "number") {
2748        time.duration = vars;
2749        vars = time;
2750        time = null;
2751      }
2752
2753      _this3 = _Animation2.call(this, skipInherit ? vars : _inheritDefaults(vars), time) || this;
2754      var _this3$vars = _this3.vars,
2755          duration = _this3$vars.duration,
2756          delay = _this3$vars.delay,
2757          immediateRender = _this3$vars.immediateRender,
2758          stagger = _this3$vars.stagger,
2759          overwrite = _this3$vars.overwrite,
2760          keyframes = _this3$vars.keyframes,
2761          defaults = _this3$vars.defaults,
2762          scrollTrigger = _this3$vars.scrollTrigger,
2763          yoyoEase = _this3$vars.yoyoEase,
2764          parent = _this3.parent,
2765          parsedTargets = (_isArray(targets) || _isTypedArray(targets) ? _isNumber(targets[0]) : "length" in vars) ? [targets] : toArray(targets),
2766          tl,
2767          i,
2768          copy,
2769          l,
2770          p,
2771          curTarget,
2772          staggerFunc,
2773          staggerVarsToMerge;
2774      _this3._targets = parsedTargets.length ? _harness(parsedTargets) : _warn("GSAP target " + targets + " not found. https://greensock.com", !_config.nullTargetWarn) || [];
2775      _this3._ptLookup = [];
2776      _this3._overwrite = overwrite;
2777
2778      if (keyframes || stagger || _isFuncOrString(duration) || _isFuncOrString(delay)) {
2779        vars = _this3.vars;
2780        tl = _this3.timeline = new Timeline({
2781          data: "nested",
2782          defaults: defaults || {}
2783        });
2784        tl.kill();
2785        tl.parent = tl._dp = _assertThisInitialized(_this3);
2786        tl._start = 0;
2787
2788        if (keyframes) {
2789          _setDefaults(tl.vars.defaults, {
2790            ease: "none"
2791          });
2792
2793          keyframes.forEach(function (frame) {
2794            return tl.to(parsedTargets, frame, ">");
2795          });
2796        } else {
2797          l = parsedTargets.length;
2798          staggerFunc = stagger ? distribute(stagger) : _emptyFunc;
2799
2800          if (_isObject(stagger)) {
2801            for (p in stagger) {
2802              if (~_staggerTweenProps.indexOf(p)) {
2803                staggerVarsToMerge || (staggerVarsToMerge = {});
2804                staggerVarsToMerge[p] = stagger[p];
2805              }
2806            }
2807          }
2808
2809          for (i = 0; i < l; i++) {
2810            copy = {};
2811
2812            for (p in vars) {
2813              if (_staggerPropsToSkip.indexOf(p) < 0) {
2814                copy[p] = vars[p];
2815              }
2816            }
2817
2818            copy.stagger = 0;
2819            yoyoEase && (copy.yoyoEase = yoyoEase);
2820            staggerVarsToMerge && _merge(copy, staggerVarsToMerge);
2821            curTarget = parsedTargets[i];
2822            copy.duration = +_parseFuncOrString(duration, _assertThisInitialized(_this3), i, curTarget, parsedTargets);
2823            copy.delay = (+_parseFuncOrString(delay, _assertThisInitialized(_this3), i, curTarget, parsedTargets) || 0) - _this3._delay;
2824
2825            if (!stagger && l === 1 && copy.delay) {
2826              _this3._delay = delay = copy.delay;
2827              _this3._start += delay;
2828              copy.delay = 0;
2829            }
2830
2831            tl.to(curTarget, copy, staggerFunc(i, curTarget, parsedTargets));
2832          }
2833
2834          tl.duration() ? duration = delay = 0 : _this3.timeline = 0;
2835        }
2836
2837        duration || _this3.duration(duration = tl.duration());
2838      } else {
2839        _this3.timeline = 0;
2840      }
2841
2842      if (overwrite === true && !_suppressOverwrites) {
2843        _overwritingTween = _assertThisInitialized(_this3);
2844
2845        _globalTimeline.killTweensOf(parsedTargets);
2846
2847        _overwritingTween = 0;
2848      }
2849
2850      parent && _postAddChecks(parent, _assertThisInitialized(_this3));
2851
2852      if (immediateRender || !duration && !keyframes && _this3._start === _round(parent._time) && _isNotFalse(immediateRender) && _hasNoPausedAncestors(_assertThisInitialized(_this3)) && parent.data !== "nested") {
2853        _this3._tTime = -_tinyNum;
2854
2855        _this3.render(Math.max(0, -delay));
2856      }
2857
2858      scrollTrigger && _scrollTrigger(_assertThisInitialized(_this3), scrollTrigger);
2859      return _this3;
2860    }
2861
2862    var _proto3 = Tween.prototype;
2863
2864    _proto3.render = function render(totalTime, suppressEvents, force) {
2865      var prevTime = this._time,
2866          tDur = this._tDur,
2867          dur = this._dur,
2868          tTime = totalTime > tDur - _tinyNum && totalTime >= 0 ? tDur : totalTime < _tinyNum ? 0 : totalTime,
2869          time,
2870          pt,
2871          iteration,
2872          cycleDuration,
2873          prevIteration,
2874          isYoyo,
2875          ratio,
2876          timeline,
2877          yoyoEase;
2878
2879      if (!dur) {
2880        _renderZeroDurationTween(this, totalTime, suppressEvents, force);
2881      } else if (tTime !== this._tTime || !totalTime || force || !this._initted && this._tTime || this._startAt && this._zTime < 0 !== totalTime < 0) {
2882        time = tTime;
2883        timeline = this.timeline;
2884
2885        if (this._repeat) {
2886          cycleDuration = dur + this._rDelay;
2887
2888          if (this._repeat < -1 && totalTime < 0) {
2889            return this.totalTime(cycleDuration * 100 + totalTime, suppressEvents, force);
2890          }
2891
2892          time = _round(tTime % cycleDuration);
2893
2894          if (tTime === tDur) {
2895            iteration = this._repeat;
2896            time = dur;
2897          } else {
2898            iteration = ~~(tTime / cycleDuration);
2899
2900            if (iteration && iteration === tTime / cycleDuration) {
2901              time = dur;
2902              iteration--;
2903            }
2904
2905            time > dur && (time = dur);
2906          }
2907
2908          isYoyo = this._yoyo && iteration & 1;
2909
2910          if (isYoyo) {
2911            yoyoEase = this._yEase;
2912            time = dur - time;
2913          }
2914
2915          prevIteration = _animationCycle(this._tTime, cycleDuration);
2916
2917          if (time === prevTime && !force && this._initted) {
2918            return this;
2919          }
2920
2921          if (iteration !== prevIteration) {
2922            timeline && this._yEase && _propagateYoyoEase(timeline, isYoyo);
2923
2924            if (this.vars.repeatRefresh && !isYoyo && !this._lock) {
2925              this._lock = force = 1;
2926              this.render(_round(cycleDuration * iteration), true).invalidate()._lock = 0;
2927            }
2928          }
2929        }
2930
2931        if (!this._initted) {
2932          if (_attemptInitTween(this, totalTime < 0 ? totalTime : time, force, suppressEvents)) {
2933            this._tTime = 0;
2934            return this;
2935          }
2936
2937          if (dur !== this._dur) {
2938            return this.render(totalTime, suppressEvents, force);
2939          }
2940        }
2941
2942        this._tTime = tTime;
2943        this._time = time;
2944
2945        if (!this._act && this._ts) {
2946          this._act = 1;
2947          this._lazy = 0;
2948        }
2949
2950        this.ratio = ratio = (yoyoEase || this._ease)(time / dur);
2951
2952        if (this._from) {
2953          this.ratio = ratio = 1 - ratio;
2954        }
2955
2956        time && !prevTime && !suppressEvents && _callback(this, "onStart");
2957        pt = this._pt;
2958
2959        while (pt) {
2960          pt.r(ratio, pt.d);
2961          pt = pt._next;
2962        }
2963
2964        timeline && timeline.render(totalTime < 0 ? totalTime : !time && isYoyo ? -_tinyNum : timeline._dur * ratio, suppressEvents, force) || this._startAt && (this._zTime = totalTime);
2965
2966        if (this._onUpdate && !suppressEvents) {
2967          totalTime < 0 && this._startAt && this._startAt.render(totalTime, true, force);
2968
2969          _callback(this, "onUpdate");
2970        }
2971
2972        this._repeat && iteration !== prevIteration && this.vars.onRepeat && !suppressEvents && this.parent && _callback(this, "onRepeat");
2973
2974        if ((tTime === this._tDur || !tTime) && this._tTime === tTime) {
2975          totalTime < 0 && this._startAt && !this._onUpdate && this._startAt.render(totalTime, true, true);
2976          (totalTime || !dur) && (tTime === this._tDur && this._ts > 0 || !tTime && this._ts < 0) && _removeFromParent(this, 1);
2977
2978          if (!suppressEvents && !(totalTime < 0 && !prevTime) && (tTime || prevTime)) {
2979            _callback(this, tTime === tDur ? "onComplete" : "onReverseComplete", true);
2980
2981            this._prom && !(tTime < tDur && this.timeScale() > 0) && this._prom();
2982          }
2983        }
2984      }
2985
2986      return this;
2987    };
2988
2989    _proto3.targets = function targets() {
2990      return this._targets;
2991    };
2992
vendor: 12,946 bytes, lines 2993-3420
2993    _proto3.invalidate = function invalidate() {
2994      this._pt = this._op = this._startAt = this._onUpdate = this._lazy = this.ratio = 0;
2995      this._ptLookup = [];
2996      this.timeline && this.timeline.invalidate();
2997      return _Animation2.prototype.invalidate.call(this);
2998    };
2999
3000    _proto3.kill = function kill(targets, vars) {
3001      if (vars === void 0) {
3002        vars = "all";
3003      }
3004
3005      if (!targets && (!vars || vars === "all")) {
3006        this._lazy = this._pt = 0;
3007        return this.parent ? _interrupt(this) : this;
3008      }
3009
3010      if (this.timeline) {
3011        var tDur = this.timeline.totalDuration();
3012        this.timeline.killTweensOf(targets, vars, _overwritingTween && _overwritingTween.vars.overwrite !== true)._first || _interrupt(this);
3013        this.parent && tDur !== this.timeline.totalDuration() && _setDuration(this, this._dur * this.timeline._tDur / tDur, 0, 1);
3014        return this;
3015      }
3016
3017      var parsedTargets = this._targets,
3018          killingTargets = targets ? toArray(targets) : parsedTargets,
3019          propTweenLookup = this._ptLookup,
3020          firstPT = this._pt,
3021          overwrittenProps,
3022          curLookup,
3023          curOverwriteProps,
3024          props,
3025          p,
3026          pt,
3027          i;
3028
3029      if ((!vars || vars === "all") && _arraysMatch(parsedTargets, killingTargets)) {
3030        vars === "all" && (this._pt = 0);
3031        return _interrupt(this);
3032      }
3033
3034      overwrittenProps = this._op = this._op || [];
3035
3036      if (vars !== "all") {
3037        if (_isString(vars)) {
3038          p = {};
3039
3040          _forEachName(vars, function (name) {
3041            return p[name] = 1;
3042          });
3043
3044          vars = p;
3045        }
3046
3047        vars = _addAliasesToVars(parsedTargets, vars);
3048      }
3049
3050      i = parsedTargets.length;
3051
3052      while (i--) {
3053        if (~killingTargets.indexOf(parsedTargets[i])) {
3054          curLookup = propTweenLookup[i];
3055
3056          if (vars === "all") {
3057            overwrittenProps[i] = vars;
3058            props = curLookup;
3059            curOverwriteProps = {};
3060          } else {
3061            curOverwriteProps = overwrittenProps[i] = overwrittenProps[i] || {};
3062            props = vars;
3063          }
3064
3065          for (p in props) {
3066            pt = curLookup && curLookup[p];
3067
3068            if (pt) {
3069              if (!("kill" in pt.d) || pt.d.kill(p) === true) {
3070                _removeLinkedListItem(this, pt, "_pt");
3071              }
3072
3073              delete curLookup[p];
3074            }
3075
3076            if (curOverwriteProps !== "all") {
3077              curOverwriteProps[p] = 1;
3078            }
3079          }
3080        }
3081      }
3082
3083      this._initted && !this._pt && firstPT && _interrupt(this);
3084      return this;
3085    };
3086
3087    Tween.to = function to(targets, vars) {
3088      return new Tween(targets, vars, arguments[2]);
3089    };
3090
3091    Tween.from = function from(targets, vars) {
3092      return new Tween(targets, _parseVars(arguments, 1));
3093    };
3094
3095    Tween.delayedCall = function delayedCall(delay, callback, params, scope) {
3096      return new Tween(callback, 0, {
3097        immediateRender: false,
3098        lazy: false,
3099        overwrite: false,
3100        delay: delay,
3101        onComplete: callback,
3102        onReverseComplete: callback,
3103        onCompleteParams: params,
3104        onReverseCompleteParams: params,
3105        callbackScope: scope
3106      });
3107    };
3108
3109    Tween.fromTo = function fromTo(targets, fromVars, toVars) {
3110      return new Tween(targets, _parseVars(arguments, 2));
3111    };
3112
3113    Tween.set = function set(targets, vars) {
3114      vars.duration = 0;
3115      vars.repeatDelay || (vars.repeat = 0);
3116      return new Tween(targets, vars);
3117    };
3118
3119    Tween.killTweensOf = function killTweensOf(targets, props, onlyActive) {
3120      return _globalTimeline.killTweensOf(targets, props, onlyActive);
3121    };
3122
3123    return Tween;
3124  }(Animation);
3125
3126  _setDefaults(Tween.prototype, {
3127    _targets: [],
3128    _lazy: 0,
3129    _startAt: 0,
3130    _op: 0,
3131    _onInit: 0
3132  });
3133
3134  _forEachName("staggerTo,staggerFrom,staggerFromTo", function (name) {
3135    Tween[name] = function () {
3136      var tl = new Timeline(),
3137          params = _slice.call(arguments, 0);
3138
3139      params.splice(name === "staggerFromTo" ? 5 : 4, 0, 0);
3140      return tl[name].apply(tl, params);
3141    };
3142  });
3143
3144  var _setterPlain = function _setterPlain(target, property, value) {
3145    return target[property] = value;
3146  },
3147      _setterFunc = function _setterFunc(target, property, value) {
3148    return target[property](value);
3149  },
3150      _setterFuncWithParam = function _setterFuncWithParam(target, property, value, data) {
3151    return target[property](data.fp, value);
3152  },
3153      _setterAttribute = function _setterAttribute(target, property, value) {
3154    return target.setAttribute(property, value);
3155  },
3156      _getSetter = function _getSetter(target, property) {
3157    return _isFunction(target[property]) ? _setterFunc : _isUndefined(target[property]) && target.setAttribute ? _setterAttribute : _setterPlain;
3158  },
3159      _renderPlain = function _renderPlain(ratio, data) {
3160    return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 10000) / 10000, data);
3161  },
3162      _renderBoolean = function _renderBoolean(ratio, data) {
3163    return data.set(data.t, data.p, !!(data.s + data.c * ratio), data);
3164  },
3165      _renderComplexString = function _renderComplexString(ratio, data) {
3166    var pt = data._pt,
3167        s = "";
3168
3169    if (!ratio && data.b) {
3170      s = data.b;
3171    } else if (ratio === 1 && data.e) {
3172      s = data.e;
3173    } else {
3174      while (pt) {
3175        s = pt.p + (pt.m ? pt.m(pt.s + pt.c * ratio) : Math.round((pt.s + pt.c * ratio) * 10000) / 10000) + s;
3176        pt = pt._next;
3177      }
3178
3179      s += data.c;
3180    }
3181
3182    data.set(data.t, data.p, s, data);
3183  },
3184      _renderPropTweens = function _renderPropTweens(ratio, data) {
3185    var pt = data._pt;
3186
3187    while (pt) {
3188      pt.r(ratio, pt.d);
3189      pt = pt._next;
3190    }
3191  },
3192      _addPluginModifier = function _addPluginModifier(modifier, tween, target, property) {
3193    var pt = this._pt,
3194        next;
3195
3196    while (pt) {
3197      next = pt._next;
3198      pt.p === property && pt.modifier(modifier, tween, target);
3199      pt = next;
3200    }
3201  },
3202      _killPropTweensOf = function _killPropTweensOf(property) {
3203    var pt = this._pt,
3204        hasNonDependentRemaining,
3205        next;
3206
3207    while (pt) {
3208      next = pt._next;
3209
3210      if (pt.p === property && !pt.op || pt.op === property) {
3211        _removeLinkedListItem(this, pt, "_pt");
3212      } else if (!pt.dep) {
3213        hasNonDependentRemaining = 1;
3214      }
3215
3216      pt = next;
3217    }
3218
3219    return !hasNonDependentRemaining;
3220  },
3221      _setterWithModifier = function _setterWithModifier(target, property, value, data) {
3222    data.mSet(target, property, data.m.call(data.tween, value, data.mt), data);
3223  },
3224      _sortPropTweensByPriority = function _sortPropTweensByPriority(parent) {
3225    var pt = parent._pt,
3226        next,
3227        pt2,
3228        first,
3229        last;
3230
3231    while (pt) {
3232      next = pt._next;
3233      pt2 = first;
3234
3235      while (pt2 && pt2.pr > pt.pr) {
3236        pt2 = pt2._next;
3237      }
3238
3239      if (pt._prev = pt2 ? pt2._prev : last) {
3240        pt._prev._next = pt;
3241      } else {
3242        first = pt;
3243      }
3244
3245      if (pt._next = pt2) {
3246        pt2._prev = pt;
3247      } else {
3248        last = pt;
3249      }
3250
3251      pt = next;
3252    }
3253
3254    parent._pt = first;
3255  };
3256
3257  var PropTween = function () {
3258    function PropTween(next, target, prop, start, change, renderer, data, setter, priority) {
3259      this.t = target;
3260      this.s = start;
3261      this.c = change;
3262      this.p = prop;
3263      this.r = renderer || _renderPlain;
3264      this.d = data || this;
3265      this.set = setter || _setterPlain;
3266      this.pr = priority || 0;
3267      this._next = next;
3268
3269      if (next) {
3270        next._prev = this;
3271      }
3272    }
3273
3274    var _proto4 = PropTween.prototype;
3275
3276    _proto4.modifier = function modifier(func, tween, target) {
3277      this.mSet = this.mSet || this.set;
3278      this.set = _setterWithModifier;
3279      this.m = func;
3280      this.mt = target;
3281      this.tween = tween;
3282    };
3283
3284    return PropTween;
3285  }();
3286
3287  _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) {
3288    return _reservedProps[name] = 1;
3289  });
3290
3291  _globals.TweenMax = _globals.TweenLite = Tween;
3292  _globals.TimelineLite = _globals.TimelineMax = Timeline;
3293  _globalTimeline = new Timeline({
3294    sortChildren: false,
3295    defaults: _defaults,
3296    autoRemoveChildren: true,
3297    id: "root",
3298    smoothChildTiming: true
3299  });
3300  _config.stringFilter = _colorStringFilter;
3301  var _gsap = {
3302    registerPlugin: function registerPlugin() {
3303      for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
3304        args[_key2] = arguments[_key2];
3305      }
3306
3307      args.forEach(function (config) {
3308        return _createPlugin(config);
3309      });
3310    },
3311    timeline: function timeline(vars) {
3312      return new Timeline(vars);
3313    },
3314    getTweensOf: function getTweensOf(targets, onlyActive) {
3315      return _globalTimeline.getTweensOf(targets, onlyActive);
3316    },
3317    getProperty: function getProperty(target, property, unit, uncache) {
3318      _isString(target) && (target = toArray(target)[0]);
3319
3320      var getter = _getCache(target || {}).get,
3321          format = unit ? _passThrough : _numericIfPossible;
3322
3323      unit === "native" && (unit = "");
3324      return !target ? target : !property ? function (property, unit, uncache) {
3325        return format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));
3326      } : format((_plugins[property] && _plugins[property].get || getter)(target, property, unit, uncache));
3327    },
3328    quickSetter: function quickSetter(target, property, unit) {
3329      target = toArray(target);
3330
3331      if (target.length > 1) {
3332        var setters = target.map(function (t) {
3333          return gsap.quickSetter(t, property, unit);
3334        }),
3335            l = setters.length;
3336        return function (value) {
3337          var i = l;
3338
3339          while (i--) {
3340            setters[i](value);
3341          }
3342        };
3343      }
3344
3345      target = target[0] || {};
3346
3347      var Plugin = _plugins[property],
3348          cache = _getCache(target),
3349          p = cache.harness && (cache.harness.aliases || {})[property] || property,
3350          setter = Plugin ? function (value) {
3351        var p = new Plugin();
3352        _quickTween._pt = 0;
3353        p.init(target, unit ? value + unit : value, _quickTween, 0, [target]);
3354        p.render(1, p);
3355        _quickTween._pt && _renderPropTweens(1, _quickTween);
3356      } : cache.set(target, p);
3357
3358      return Plugin ? setter : function (value) {
3359        return setter(target, p, unit ? value + unit : value, cache, 1);
3360      };
3361    },
3362    isTweening: function isTweening(targets) {
3363      return _globalTimeline.getTweensOf(targets, true).length > 0;
3364    },
3365    defaults: function defaults(value) {
3366      value && value.ease && (value.ease = _parseEase(value.ease, _defaults.ease));
3367      return _mergeDeep(_defaults, value || {});
3368    },
3369    config: function config(value) {
3370      return _mergeDeep(_config, value || {});
3371    },
3372    registerEffect: function registerEffect(_ref2) {
3373      var name = _ref2.name,
3374          effect = _ref2.effect,
3375          plugins = _ref2.plugins,
3376          defaults = _ref2.defaults,
3377          extendTimeline = _ref2.extendTimeline;
3378      (plugins || "").split(",").forEach(function (pluginName) {
3379        return pluginName && !_plugins[pluginName] && !_globals[pluginName] && _warn(name + " effect requires " + pluginName + " plugin.");
3380      });
3381
3382      _effects[name] = function (targets, vars, tl) {
3383        return effect(toArray(targets), _setDefaults(vars || {}, defaults), tl);
3384      };
3385
3386      if (extendTimeline) {
3387        Timeline.prototype[name] = function (targets, vars, position) {
3388          return this.add(_effects[name](targets, _isObject(vars) ? vars : (position = vars) && {}, this), position);
3389        };
3390      }
3391    },
3392    registerEase: function registerEase(name, ease) {
3393      _easeMap[name] = _parseEase(ease);
3394    },
3395    parseEase: function parseEase(ease, defaultEase) {
3396      return arguments.length ? _parseEase(ease, defaultEase) : _easeMap;
3397    },
3398    getById: function getById(id) {
3399      return _globalTimeline.getById(id);
3400    },
3401    exportRoot: function exportRoot(vars, includeDelayedCalls) {
3402      if (vars === void 0) {
3403        vars = {};
3404      }
3405
3406      var tl = new Timeline(vars),
3407          child,
3408          next;
3409      tl.smoothChildTiming = _isNotFalse(vars.smoothChildTiming);
3410
3411      _globalTimeline.remove(tl);
3412
3413      tl._dp = 0;
3414      tl._time = tl._tTime = _globalTimeline._time;
3415      child = _globalTimeline._first;
3416
3417      while (child) {
3418        next = child._next;
3419
3420        if (includeDelayedCalls || !(!child._dur && child instanceof Tween && child.vars.onComplete === child._targets[0])) {
3421          _addToTimeline(tl, child, child._start - child._delay);
3422        }
3423
3424        child = next;
3425      }
3426
3427      _addToTimeline(_globalTimeline, tl, 0);
3428
3429      return tl;
3430    },
3431    utils: {
3432      wrap: wrap,
3433      wrapYoyo: wrapYoyo,
3434      distribute: distribute,
3435      random: random,
3436      snap: snap,
3437      normalize: normalize,
3438      getUnit: getUnit,
3439      clamp: clamp,
3440      splitColor: splitColor,
3441      toArray: toArray,
3442      mapRange: mapRange,
3443      pipe: pipe,
3444      unitize: unitize,
3445      interpolate: interpolate,
3446      shuffle: shuffle
3447    },
3448    install: _install,
3449    effects: _effects,
3450    ticker: _ticker,
3451    updateRoot: Timeline.updateRoot,
3452    plugins: _plugins,
3453    globalTimeline: _globalTimeline,
3454    core: {
3455      PropTween: PropTween,
3456      globals: _addGlobal,
3457      Tween: Tween,
3458      Timeline: Timeline,
3459      Animation: Animation,
3460      getCache: _getCache,
3461      _removeLinkedListItem: _removeLinkedListItem,
3462      suppressOverwrites: function suppressOverwrites(value) {
3463        return _suppressOverwrites = value;
3464      }
3465    }
3466  };
3467
3468  _forEachName("to,from,fromTo,delayedCall,set,killTweensOf", function (name) {
3469    return _gsap[name] = Tween[name];
3470  });
3471
3472  _ticker.add(Timeline.updateRoot);
3473
3474  _quickTween = _gsap.to({}, {
3475    duration: 0
3476  });
3477
3478  var _getPluginPropTween = function _getPluginPropTween(plugin, prop
vendor: 18,114 bytes, lines 3478-4050
3478) {
3479    var pt = plugin._pt;
3480
3481    while (pt && pt.p !== prop && pt.op !== prop && pt.fp !== prop) {
3482      pt = pt._next;
3483    }
3484
3485    return pt;
3486  },
3487      _addModifiers = function _addModifiers(tween, modifiers) {
3488    var targets = tween._targets,
3489        p,
3490        i,
3491        pt;
3492
3493    for (p in modifiers) {
3494      i = targets.length;
3495
3496      while (i--) {
3497        pt = tween._ptLookup[i][p];
3498
3499        if (pt && (pt = pt.d)) {
3500          if (pt._pt) {
3501            pt = _getPluginPropTween(pt, p);
3502          }
3503
3504          pt && pt.modifier && pt.modifier(modifiers[p], tween, targets[i], p);
3505        }
3506      }
3507    }
3508  },
3509      _buildModifierPlugin = function _buildModifierPlugin(name, modifier) {
3510    return {
3511      name: name,
3512      rawVars: 1,
3513      init: function init(target, vars, tween) {
3514        tween._onInit = function (tween) {
3515          var temp, p;
3516
3517          if (_isString(vars)) {
3518            temp = {};
3519
3520            _forEachName(vars, function (name) {
3521              return temp[name] = 1;
3522            });
3523
3524            vars = temp;
3525          }
3526
3527          if (modifier) {
3528            temp = {};
3529
3530            for (p in vars) {
3531              temp[p] = modifier(vars[p]);
3532            }
3533
3534            vars = temp;
3535          }
3536
3537          _addModifiers(tween, vars);
3538        };
3539      }
3540    };
3541  };
3542
3543  var gsap = _gsap.registerPlugin({
3544    name: "attr",
3545    init: function init(target, vars, tween, index, targets) {
3546      var p, pt;
3547
3548      for (p in vars) {
3549        pt = this.add(target, "setAttribute", (target.getAttribute(p) || 0) + "", vars[p], index, targets, 0, 0, p);
3550        pt && (pt.op = p);
3551
3552        this._props.push(p);
3553      }
3554    }
3555  }, {
3556    name: "endArray",
3557    init: function init(target, value) {
3558      var i = value.length;
3559
3560      while (i--) {
3561        this.add(target, i, target[i] || 0, value[i]);
3562      }
3563    }
3564  }, _buildModifierPlugin("roundProps", _roundModifier), _buildModifierPlugin("modifiers"), _buildModifierPlugin("snap", snap)) || _gsap;
3565  Tween.version = Timeline.version = gsap.version = "3.6.1";
3566  _coreReady = 1;
3567
3568  if (_windowExists()) {
3569    _wake();
3570  }
3571
3572  var Power0 = _easeMap.Power0,
3573      Power1 = _easeMap.Power1,
3574      Power2 = _easeMap.Power2,
3575      Power3 = _easeMap.Power3,
3576      Power4 = _easeMap.Power4,
3577      Linear = _easeMap.Linear,
3578      Quad = _easeMap.Quad,
3579      Cubic = _easeMap.Cubic,
3580      Quart = _easeMap.Quart,
3581      Quint = _easeMap.Quint,
3582      Strong = _easeMap.Strong,
3583      Elastic = _easeMap.Elastic,
3584      Back = _easeMap.Back,
3585      SteppedEase = _easeMap.SteppedEase,
3586      Bounce = _easeMap.Bounce,
3587      Sine = _easeMap.Sine,
3588      Expo = _easeMap.Expo,
3589      Circ = _easeMap.Circ;
3590
3591  var _win$1,
3592      _doc$1,
3593      _docElement,
3594      _pluginInitted,
3595      _tempDiv,
3596      _tempDivStyler,
3597      _recentSetterPlugin,
3598      _windowExists$1 = function _windowExists() {
3599    return typeof window !== "undefined";
3600  },
3601      _transformProps = {},
3602      _RAD2DEG = 180 / Math.PI,
3603      _DEG2RAD = Math.PI / 180,
3604      _atan2 = Math.atan2,
3605      _bigNum$1 = 1e8,
3606      _capsExp = /([A-Z])/g,
3607      _horizontalExp = /(?:left|right|width|margin|padding|x)/i,
3608      _complexExp = /[\s,\(]\S/,
3609      _propertyAliases = {
3610    autoAlpha: "opacity,visibility",
3611    scale: "scaleX,scaleY",
3612    alpha: "opacity"
3613  },
3614      _renderCSSProp = function _renderCSSProp(ratio, data) {
3615    return data.set(data.t, data.p, Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);
3616  },
3617      _renderPropWithEnd = function _renderPropWithEnd(ratio, data) {
3618    return data.set(data.t, data.p, ratio === 1 ? data.e : Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u, data);
3619  },
3620      _renderCSSPropWithBeginning = function _renderCSSPropWithBeginning(ratio, data) {
3621    return data.set(data.t, data.p, ratio ? Math.round((data.s + data.c * ratio) * 10000) / 10000 + data.u : data.b, data);
3622  },
3623      _renderRoundedCSSProp = function _renderRoundedCSSProp(ratio, data) {
3624    var value = data.s + data.c * ratio;
3625    data.set(data.t, data.p, ~~(value + (value < 0 ? -.5 : .5)) + data.u, data);
3626  },
3627      _renderNonTweeningValue = function _renderNonTweeningValue(ratio, data) {
3628    return data.set(data.t, data.p, ratio ? data.e : data.b, data);
3629  },
3630      _renderNonTweeningValueOnlyAtEnd = function _renderNonTweeningValueOnlyAtEnd(ratio, data) {
3631    return data.set(data.t, data.p, ratio !== 1 ? data.b : data.e, data);
3632  },
3633      _setterCSSStyle = function _setterCSSStyle(target, property, value) {
3634    return target.style[property] = value;
3635  },
3636      _setterCSSProp = function _setterCSSProp(target, property, value) {
3637    return target.style.setProperty(property, value);
3638  },
3639      _setterTransform = function _setterTransform(target, property, value) {
3640    return target._gsap[property] = value;
3641  },
3642      _setterScale = function _setterScale(target, property, value) {
3643    return target._gsap.scaleX = target._gsap.scaleY = value;
3644  },
3645      _setterScaleWithRender = function _setterScaleWithRender(target, property, value, data, ratio) {
3646    var cache = target._gsap;
3647    cache.scaleX = cache.scaleY = value;
3648    cache.renderTransform(ratio, cache);
3649  },
3650      _setterTransformWithRender = function _setterTransformWithRender(target, property, value, data, ratio) {
3651    var cache = target._gsap;
3652    cache[property] = value;
3653    cache.renderTransform(ratio, cache);
3654  },
3655      _transformProp = "transform",
3656      _transformOriginProp = _transformProp + "Origin",
3657      _supports3D,
3658      _createElement = function _createElement(type, ns) {
3659    var e = _doc$1.createElementNS ? _doc$1.createElementNS((ns || "http://www.w3.org/1999/xhtml").replace(/^https/, "http"), type) : _doc$1.createElement(type);
3660    return e.style ? e : _doc$1.createElement(type);
3661  },
3662      _getComputedProperty = function _getComputedProperty(target, property, skipPrefixFallback) {
3663    var cs = getComputedStyle(target);
3664    return cs[property] || cs.getPropertyValue(property.replace(_capsExp, "-$1").toLowerCase()) || cs.getPropertyValue(property) || !skipPrefixFallback && _getComputedProperty(target, _checkPropPrefix(property) || property, 1) || "";
3665  },
3666      _prefixes = "O,Moz,ms,Ms,Webkit".split(","),
3667      _checkPropPrefix = function _checkPropPrefix(property, element, preferPrefix) {
3668    var e = element || _tempDiv,
3669        s = e.style,
3670        i = 5;
3671
3672    if (property in s && !preferPrefix) {
3673      return property;
3674    }
3675
3676    property = property.charAt(0).toUpperCase() + property.substr(1);
3677
3678    while (i-- && !(_prefixes[i] + property in s)) {}
3679
3680    return i < 0 ? null : (i === 3 ? "ms" : i >= 0 ? _prefixes[i] : "") + property;
3681  },
3682      _initCore = function _initCore() {
3683    if (_windowExists$1() && window.document) {
3684      _win$1 = window;
3685      _doc$1 = _win$1.document;
3686      _docElement = _doc$1.documentElement;
3687      _tempDiv = _createElement("div") || {
3688        style: {}
3689      };
3690      _tempDivStyler = _createElement("div");
3691      _transformProp = _checkPropPrefix(_transformProp);
3692      _transformOriginProp = _transformProp + "Origin";
3693      _tempDiv.style.cssText = "border-width:0;line-height:0;position:absolute;padding:0";
3694      _supports3D = !!_checkPropPrefix("perspective");
3695      _pluginInitted = 1;
3696    }
3697  },
3698      _getBBoxHack = function _getBBoxHack(swapIfPossible) {
3699    var svg = _createElement("svg", this.ownerSVGElement && this.ownerSVGElement.getAttribute("xmlns") || "http://www.w3.org/2000/svg"),
3700        oldParent = this.parentNode,
3701        oldSibling = this.nextSibling,
3702        oldCSS = this.style.cssText,
3703        bbox;
3704
3705    _docElement.appendChild(svg);
3706
3707    svg.appendChild(this);
3708    this.style.display = "block";
3709
3710    if (swapIfPossible) {
3711      try {
3712        bbox = this.getBBox();
3713        this._gsapBBox = this.getBBox;
3714        this.getBBox = _getBBoxHack;
3715      } catch (e) {}
3716    } else if (this._gsapBBox) {
3717      bbox = this._gsapBBox();
3718    }
3719
3720    if (oldParent) {
3721      if (oldSibling) {
3722        oldParent.insertBefore(this, oldSibling);
3723      } else {
3724        oldParent.appendChild(this);
3725      }
3726    }
3727
3728    _docElement.removeChild(svg);
3729
3730    this.style.cssText = oldCSS;
3731    return bbox;
3732  },
3733      _getAttributeFallbacks = function _getAttributeFallbacks(target, attributesArray) {
3734    var i = attributesArray.length;
3735
3736    while (i--) {
3737      if (target.hasAttribute(attributesArray[i])) {
3738        return target.getAttribute(attributesArray[i]);
3739      }
3740    }
3741  },
3742      _getBBox = function _getBBox(target) {
3743    var bounds;
3744
3745    try {
3746      bounds = target.getBBox();
3747    } catch (error) {
3748      bounds = _getBBoxHack.call(target, true);
3749    }
3750
3751    bounds && (bounds.width || bounds.height) || target.getBBox === _getBBoxHack || (bounds = _getBBoxHack.call(target, true));
3752    return bounds && !bounds.width && !bounds.x && !bounds.y ? {
3753      x: +_getAttributeFallbacks(target, ["x", "cx", "x1"]) || 0,
3754      y: +_getAttributeFallbacks(target, ["y", "cy", "y1"]) || 0,
3755      width: 0,
3756      height: 0
3757    } : bounds;
3758  },
3759      _isSVG = function _isSVG(e) {
3760    return !!(e.getCTM && (!e.parentNode || e.ownerSVGElement) && _getBBox(e));
3761  },
3762      _removeProperty = function _removeProperty(target, property) {
3763    if (property) {
3764      var style = target.style;
3765
3766      if (property in _transformProps && property !== _transformOriginProp) {
3767        property = _transformProp;
3768      }
3769
3770      if (style.removeProperty) {
3771        if (property.substr(0, 2) === "ms" || property.substr(0, 6) === "webkit") {
3772          property = "-" + property;
3773        }
3774
3775        style.removeProperty(property.replace(_capsExp, "-$1").toLowerCase());
3776      } else {
3777        style.removeAttribute(property);
3778      }
3779    }
3780  },
3781      _addNonTweeningPT = function _addNonTweeningPT(plugin, target, property, beginning, end, onlySetAtEnd) {
3782    var pt = new PropTween(plugin._pt, target, property, 0, 1, onlySetAtEnd ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue);
3783    plugin._pt = pt;
3784    pt.b = beginning;
3785    pt.e = end;
3786
3787    plugin._props.push(property);
3788
3789    return pt;
3790  },
3791      _nonConvertibleUnits = {
3792    deg: 1,
3793    rad: 1,
3794    turn: 1
3795  },
3796      _convertToUnit = function _convertToUnit(target, property, value, unit) {
3797    var curValue = parseFloat(value) || 0,
3798        curUnit = (value + "").trim().substr((curValue + "").length) || "px",
3799        style = _tempDiv.style,
3800        horizontal = _horizontalExp.test(property),
3801        isRootSVG = target.tagName.toLowerCase() === "svg",
3802        measureProperty = (isRootSVG ? "client" : "offset") + (horizontal ? "Width" : "Height"),
3803        amount = 100,
3804        toPixels = unit === "px",
3805        toPercent = unit === "%",
3806        px,
3807        parent,
3808        cache,
3809        isSVG;
3810
3811    if (unit === curUnit || !curValue || _nonConvertibleUnits[unit] || _nonConvertibleUnits[curUnit]) {
3812      return curValue;
3813    }
3814
3815    curUnit !== "px" && !toPixels && (curValue = _convertToUnit(target, property, value, "px"));
3816    isSVG = target.getCTM && _isSVG(target);
3817
3818    if ((toPercent || curUnit === "%") && (_transformProps[property] || ~property.indexOf("adius"))) {
3819      px = isSVG ? target.getBBox()[horizontal ? "width" : "height"] : target[measureProperty];
3820      return _round(toPercent ? curValue / px * amount : curValue / 100 * px);
3821    }
3822
3823    style[horizontal ? "width" : "height"] = amount + (toPixels ? curUnit : unit);
3824    parent = ~property.indexOf("adius") || unit === "em" && target.appendChild && !isRootSVG ? target : target.parentNode;
3825
3826    if (isSVG) {
3827      parent = (target.ownerSVGElement || {}).parentNode;
3828    }
3829
3830    if (!parent || parent === _doc$1 || !parent.appendChild) {
3831      parent = _doc$1.body;
3832    }
3833
3834    cache = parent._gsap;
3835
3836    if (cache && toPercent && cache.width && horizontal && cache.time === _ticker.time) {
3837      return _round(curValue / cache.width * amount);
3838    } else {
3839      (toPercent || curUnit === "%") && (style.position = _getComputedProperty(target, "position"));
3840      parent === target && (style.position = "static");
3841      parent.appendChild(_tempDiv);
3842      px = _tempDiv[measureProperty];
3843      parent.removeChild(_tempDiv);
3844      style.position = "absolute";
3845
3846      if (horizontal && toPercent) {
3847        cache = _getCache(parent);
3848        cache.time = _ticker.time;
3849        cache.width = parent[measureProperty];
3850      }
3851    }
3852
3853    return _round(toPixels ? px * curValue / amount : px && curValue ? amount / px * curValue : 0);
3854  },
3855      _get = function _get(target, property, unit, uncache) {
3856    var value;
3857    _pluginInitted || _initCore();
3858
3859    if (property in _propertyAliases && property !== "transform") {
3860      property = _propertyAliases[property];
3861
3862      if (~property.indexOf(",")) {
3863        property = property.split(",")[0];
3864      }
3865    }
3866
3867    if (_transformProps[property] && property !== "transform") {
3868      value = _parseTransform(target, uncache);
3869      value = property !== "transformOrigin" ? value[property] : _firstTwoOnly(_getComputedProperty(target, _transformOriginProp)) + " " + value.zOrigin + "px";
3870    } else {
3871      value = target.style[property];
3872
3873      if (!value || value === "auto" || uncache || ~(value + "").indexOf("calc(")) {
3874        value = _specialProps[property] && _specialProps[property](target, property, unit) || _getComputedProperty(target, property) || _getProperty(target, property) || (property === "opacity" ? 1 : 0);
3875      }
3876    }
3877
3878    return unit && !~(value + "").trim().indexOf(" ") ? _convertToUnit(target, property, value, unit) + unit : value;
3879  },
3880      _tweenComplexCSSString = function _tweenComplexCSSString(target, prop, start, end) {
3881    if (!start || start === "none") {
3882      var p = _checkPropPrefix(prop, target, 1),
3883          s = p && _getComputedProperty(target, p, 1);
3884
3885      if (s && s !== start) {
3886        prop = p;
3887        start = s;
3888      } else if (prop === "borderColor") {
3889        start = _getComputedProperty(target, "borderTopColor");
3890      }
3891    }
3892
3893    var pt = new PropTween(this._pt, target.style, prop, 0, 1, _renderComplexString),
3894        index = 0,
3895        matchIndex = 0,
3896        a,
3897        result,
3898        startValues,
3899        startNum,
3900        color,
3901        startValue,
3902        endValue,
3903        endNum,
3904        chunk,
3905        endUnit,
3906        startUnit,
3907        relative,
3908        endValues;
3909    pt.b = start;
3910    pt.e = end;
3911    start += "";
3912    end += "";
3913
3914    if (end === "auto") {
3915      target.style[prop] = end;
3916      end = _getComputedProperty(target, prop) || end;
3917      target.style[prop] = start;
3918    }
3919
3920    a = [start, end];
3921
3922    _colorStringFilter(a);
3923
3924    start = a[0];
3925    end = a[1];
3926    startValues = start.match(_numWithUnitExp) || [];
3927    endValues = end.match(_numWithUnitExp) || [];
3928
3929    if (endValues.length) {
3930      while (result = _numWithUnitExp.exec(end)) {
3931        endValue = result[0];
3932        chunk = end.substring(index, result.index);
3933
3934        if (color) {
3935          color = (color + 1) % 5;
3936        } else if (chunk.substr(-5) === "rgba(" || chunk.substr(-5) === "hsla(") {
3937          color = 1;
3938        }
3939
3940        if (endValue !== (startValue = startValues[matchIndex++] || "")) {
3941          startNum = parseFloat(startValue) || 0;
3942          startUnit = startValue.substr((startNum + "").length);
3943          relative = endValue.charAt(1) === "=" ? +(endValue.charAt(0) + "1") : 0;
3944
3945          if (relative) {
3946            endValue = endValue.substr(2);
3947          }
3948
3949          endNum = parseFloat(endValue);
3950          endUnit = endValue.substr((endNum + "").length);
3951          index = _numWithUnitExp.lastIndex - endUnit.length;
3952
3953          if (!endUnit) {
3954            endUnit = endUnit || _config.units[prop] || startUnit;
3955
3956            if (index === end.length) {
3957              end += endUnit;
3958              pt.e += endUnit;
3959            }
3960          }
3961
3962          if (startUnit !== endUnit) {
3963            startNum = _convertToUnit(target, prop, startValue, endUnit) || 0;
3964          }
3965
3966          pt._pt = {
3967            _next: pt._pt,
3968            p: chunk || matchIndex === 1 ? chunk : ",",
3969            s: startNum,
3970            c: relative ? relative * endNum : endNum - startNum,
3971            m: color && color < 4 || prop === "zIndex" ? Math.round : 0
3972          };
3973        }
3974      }
3975
3976      pt.c = index < end.length ? end.substring(index, end.length) : "";
3977    } else {
3978      pt.r = prop === "display" && end === "none" ? _renderNonTweeningValueOnlyAtEnd : _renderNonTweeningValue;
3979    }
3980
3981    _relExp.test(end) && (pt.e = 0);
3982    this._pt = pt;
3983    return pt;
3984  },
3985      _keywordToPercent = {
3986    top: "0%",
3987    bottom: "100%",
3988    left: "0%",
3989    right: "100%",
3990    center: "50%"
3991  },
3992      _convertKeywordsToPercentages = function _convertKeywordsToPercentages(value) {
3993    var split = value.split(" "),
3994        x = split[0],
3995        y = split[1] || "50%";
3996
3997    if (x === "top" || x === "bottom" || y === "left" || y === "right") {
3998      value = x;
3999      x = y;
4000      y = value;
4001    }
4002
4003    split[0] = _keywordToPercent[x] || x;
4004    split[1] = _keywordToPercent[y] || y;
4005    return split.join(" ");
4006  },
4007      _renderClearProps = function _renderClearProps(ratio, data) {
4008    if (data.tween && data.tween._time === data.tween._dur) {
4009      var target = data.t,
4010          style = target.style,
4011          props = data.u,
4012          cache = target._gsap,
4013          prop,
4014          clearTransforms,
4015          i;
4016
4017      if (props === "all" || props === true) {
4018        style.cssText = "";
4019        clearTransforms = 1;
4020      } else {
4021        props = props.split(",");
4022        i = props.length;
4023
4024        while (--i > -1) {
4025          prop = props[i];
4026
4027          if (_transformProps[prop]) {
4028            clearTransforms = 1;
4029            prop = prop === "transformOrigin" ? _transformOriginProp : _transformProp;
4030          }
4031
4032          _removeProperty(target, prop);
4033        }
4034      }
4035
4036      if (clearTransforms) {
4037        _removeProperty(target, _transformProp);
4038
4039        if (cache) {
4040          cache.svg && target.removeAttribute("transform");
4041
4042          _parseTransform(target, 1);
4043
4044          cache.uncache = 1;
4045        }
4046      }
4047    }
4048  },
4049      _specialProps = {
4050    clearProps: function clearProps(plugin, target, property, endValue, tween) {
vendor: 3,001 bytes, lines 4051-4131
4051      if (tween.data !== "isFromStart") {
4052        var pt = plugin._pt = new PropTween(plugin._pt, target, property, 0, 0, _renderClearProps);
4053        pt.u = endValue;
4054        pt.pr = -10;
4055        pt.tween = tween;
4056
4057        plugin._props.push(property);
4058
4059        return 1;
4060      }
4061    }
4062  },
4063      _identity2DMatrix = [1, 0, 0, 1, 0, 0],
4064      _rotationalProperties = {},
4065      _isNullTransform = function _isNullTransform(value) {
4066    return value === "matrix(1, 0, 0, 1, 0, 0)" || value === "none" || !value;
4067  },
4068      _getComputedTransformMatrixAsArray = function _getComputedTransformMatrixAsArray(target) {
4069    var matrixString = _getComputedProperty(target, _transformProp);
4070
4071    return _isNullTransform(matrixString) ? _identity2DMatrix : matrixString.substr(7).match(_numExp).map(_round);
4072  },
4073      _getMatrix = function _getMatrix(target, force2D) {
4074    var cache = target._gsap || _getCache(target),
4075        style = target.style,
4076        matrix = _getComputedTransformMatrixAsArray(target),
4077        parent,
4078        nextSibling,
4079        temp,
4080        addedToDOM;
4081
4082    if (cache.svg && target.getAttribute("transform")) {
4083      temp = target.transform.baseVal.consolidate().matrix;
4084      matrix = [temp.a, temp.b, temp.c, temp.d, temp.e, temp.f];
4085      return matrix.join(",") === "1,0,0,1,0,0" ? _identity2DMatrix : matrix;
4086    } else if (matrix === _identity2DMatrix && !target.offsetParent && target !== _docElement && !cache.svg) {
4087      temp = style.display;
4088      style.display = "block";
4089      parent = target.parentNode;
4090
4091      if (!parent || !target.offsetParent) {
4092        addedToDOM = 1;
4093        nextSibling = target.nextSibling;
4094
4095        _docElement.appendChild(target);
4096      }
4097
4098      matrix = _getComputedTransformMatrixAsArray(target);
4099      temp ? style.display = temp : _removeProperty(target, "display");
4100
4101      if (addedToDOM) {
4102        nextSibling ? parent.insertBefore(target, nextSibling) : parent ? parent.appendChild(target) : _docElement.removeChild(target);
4103      }
4104    }
4105
4106    return force2D && matrix.length > 6 ? [matrix[0], matrix[1], matrix[4], matrix[5], matrix[12], matrix[13]] : matrix;
4107  },
4108      _applySVGOrigin = function _applySVGOrigin(target, origin, originIsAbsolute, smooth, matrixArray, pluginToAddPropTweensTo) {
4109    var cache = target._gsap,
4110        matrix = matrixArray || _getMatrix(target, true),
4111        xOriginOld = cache.xOrigin || 0,
4112        yOriginOld = cache.yOrigin || 0,
4113        xOffsetOld = cache.xOffset || 0,
4114        yOffsetOld = cache.yOffset || 0,
4115        a = matrix[0],
4116        b = matrix[1],
4117        c = matrix[2],
4118        d = matrix[3],
4119        tx = matrix[4],
4120        ty = matrix[5],
4121        originSplit = origin.split(" "),
4122        xOrigin = parseFloat(originSplit[0]) || 0,
4123        yOrigin = parseFloat(originSplit[1]) || 0,
4124        bounds,
4125        determinant,
4126        x,
4127        y;
4128
4129    if (!originIsAbsolute) {
4130      bounds = _getBBox(target);
4131      xOrigin = bounds.x + (~originSplit[0].indexOf("%") ? xOrigin / 100 * boun
vendor: 6,518 bytes, lines 4131-4339
4131ds.width : xOrigin);
4132      yOrigin = bounds.y + (~(originSplit[1] || originSplit[0]).indexOf("%") ? yOrigin / 100 * bounds.height : yOrigin);
4133    } else if (matrix !== _identity2DMatrix && (determinant = a * d - b * c)) {
4134      x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + (c * ty - d * tx) / determinant;
4135      y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - (a * ty - b * tx) / determinant;
4136      xOrigin = x;
4137      yOrigin = y;
4138    }
4139
4140    if (smooth || smooth !== false && cache.smooth) {
4141      tx = xOrigin - xOriginOld;
4142      ty = yOrigin - yOriginOld;
4143      cache.xOffset = xOffsetOld + (tx * a + ty * c) - tx;
4144      cache.yOffset = yOffsetOld + (tx * b + ty * d) - ty;
4145    } else {
4146      cache.xOffset = cache.yOffset = 0;
4147    }
4148
4149    cache.xOrigin = xOrigin;
4150    cache.yOrigin = yOrigin;
4151    cache.smooth = !!smooth;
4152    cache.origin = origin;
4153    cache.originIsAbsolute = !!originIsAbsolute;
4154    target.style[_transformOriginProp] = "0px 0px";
4155
4156    if (pluginToAddPropTweensTo) {
4157      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOrigin", xOriginOld, xOrigin);
4158
4159      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOrigin", yOriginOld, yOrigin);
4160
4161      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "xOffset", xOffsetOld, cache.xOffset);
4162
4163      _addNonTweeningPT(pluginToAddPropTweensTo, cache, "yOffset", yOffsetOld, cache.yOffset);
4164    }
4165
4166    target.setAttribute("data-svg-origin", xOrigin + " " + yOrigin);
4167  },
4168      _parseTransform = function _parseTransform(target, uncache) {
4169    var cache = target._gsap || new GSCache(target);
4170
4171    if ("x" in cache && !uncache && !cache.uncache) {
4172      return cache;
4173    }
4174
4175    var style = target.style,
4176        invertedScaleX = cache.scaleX < 0,
4177        px = "px",
4178        deg = "deg",
4179        origin = _getComputedProperty(target, _transformOriginProp) || "0",
4180        x,
4181        y,
4182        z,
4183        scaleX,
4184        scaleY,
4185        rotation,
4186        rotationX,
4187        rotationY,
4188        skewX,
4189        skewY,
4190        perspective,
4191        xOrigin,
4192        yOrigin,
4193        matrix,
4194        angle,
4195        cos,
4196        sin,
4197        a,
4198        b,
4199        c,
4200        d,
4201        a12,
4202        a22,
4203        t1,
4204        t2,
4205        t3,
4206        a13,
4207        a23,
4208        a33,
4209        a42,
4210        a43,
4211        a32;
4212    x = y = z = rotation = rotationX = rotationY = skewX = skewY = perspective = 0;
4213    scaleX = scaleY = 1;
4214    cache.svg = !!(target.getCTM && _isSVG(target));
4215    matrix = _getMatrix(target, cache.svg);
4216
4217    if (cache.svg) {
4218      t1 = !cache.uncache && !uncache && target.getAttribute("data-svg-origin");
4219
4220      _applySVGOrigin(target, t1 || origin, !!t1 || cache.originIsAbsolute, cache.smooth !== false, matrix);
4221    }
4222
4223    xOrigin = cache.xOrigin || 0;
4224    yOrigin = cache.yOrigin || 0;
4225
4226    if (matrix !== _identity2DMatrix) {
4227      a = matrix[0];
4228      b = matrix[1];
4229      c = matrix[2];
4230      d = matrix[3];
4231      x = a12 = matrix[4];
4232      y = a22 = matrix[5];
4233
4234      if (matrix.length === 6) {
4235        scaleX = Math.sqrt(a * a + b * b);
4236        scaleY = Math.sqrt(d * d + c * c);
4237        rotation = a || b ? _atan2(b, a) * _RAD2DEG : 0;
4238        skewX = c || d ? _atan2(c, d) * _RAD2DEG + rotation : 0;
4239        skewX && (scaleY *= Math.abs(Math.cos(skewX * _DEG2RAD)));
4240
4241        if (cache.svg) {
4242          x -= xOrigin - (xOrigin * a + yOrigin * c);
4243          y -= yOrigin - (xOrigin * b + yOrigin * d);
4244        }
4245      } else {
4246        a32 = matrix[6];
4247        a42 = matrix[7];
4248        a13 = matrix[8];
4249        a23 = matrix[9];
4250        a33 = matrix[10];
4251        a43 = matrix[11];
4252        x = matrix[12];
4253        y = matrix[13];
4254        z = matrix[14];
4255        angle = _atan2(a32, a33);
4256        rotationX = angle * _RAD2DEG;
4257
4258        if (angle) {
4259          cos = Math.cos(-angle);
4260          sin = Math.sin(-angle);
4261          t1 = a12 * cos + a13 * sin;
4262          t2 = a22 * cos + a23 * sin;
4263          t3 = a32 * cos + a33 * sin;
4264          a13 = a12 * -sin + a13 * cos;
4265          a23 = a22 * -sin + a23 * cos;
4266          a33 = a32 * -sin + a33 * cos;
4267          a43 = a42 * -sin + a43 * cos;
4268          a12 = t1;
4269          a22 = t2;
4270          a32 = t3;
4271        }
4272
4273        angle = _atan2(-c, a33);
4274        rotationY = angle * _RAD2DEG;
4275
4276        if (angle) {
4277          cos = Math.cos(-angle);
4278          sin = Math.sin(-angle);
4279          t1 = a * cos - a13 * sin;
4280          t2 = b * cos - a23 * sin;
4281          t3 = c * cos - a33 * sin;
4282          a43 = d * sin + a43 * cos;
4283          a = t1;
4284          b = t2;
4285          c = t3;
4286        }
4287
4288        angle = _atan2(b, a);
4289        rotation = angle * _RAD2DEG;
4290
4291        if (angle) {
4292          cos = Math.cos(angle);
4293          sin = Math.sin(angle);
4294          t1 = a * cos + b * sin;
4295          t2 = a12 * cos + a22 * sin;
4296          b = b * cos - a * sin;
4297          a22 = a22 * cos - a12 * sin;
4298          a = t1;
4299          a12 = t2;
4300        }
4301
4302        if (rotationX && Math.abs(rotationX) + Math.abs(rotation) > 359.9) {
4303          rotationX = rotation = 0;
4304          rotationY = 180 - rotationY;
4305        }
4306
4307        scaleX = _round(Math.sqrt(a * a + b * b + c * c));
4308        scaleY = _round(Math.sqrt(a22 * a22 + a32 * a32));
4309        angle = _atan2(a12, a22);
4310        skewX = Math.abs(angle) > 0.0002 ? angle * _RAD2DEG : 0;
4311        perspective = a43 ? 1 / (a43 < 0 ? -a43 : a43) : 0;
4312      }
4313
4314      if (cache.svg) {
4315        t1 = target.getAttribute("transform");
4316        cache.forceCSS = target.setAttribute("transform", "") || !_isNullTransform(_getComputedProperty(target, _transformProp));
4317        t1 && target.setAttribute("transform", t1);
4318      }
4319    }
4320
4321    if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) {
4322      if (invertedScaleX) {
4323        scaleX *= -1;
4324        skewX += rotation <= 0 ? 180 : -180;
4325        rotation += rotation <= 0 ? 180 : -180;
4326      } else {
4327        scaleY *= -1;
4328        skewX += skewX <= 0 ? 180 : -180;
4329      }
4330    }
4331
4332    cache.x = x - ((cache.xPercent = x && (cache.xPercent || (Math.round(target.offsetWidth / 2) === Math.round(-x) ? -50 : 0))) ? target.offsetWidth * cache.xPercent / 100 : 0) + px;
4333    cache.y = y - ((cache.yPercent = y && (cache.yPercent || (Math.round(target.offsetHeight / 2) === Math.round(-y) ? -50 : 0))) ? target.offsetHeight * cache.yPercent / 100 : 0) + px;
4334    cache.z = z + px;
4335    cache.scaleX = _round(scaleX);
4336    cache.scaleY = _round(scaleY);
4337    cache.rotation = _round(rotation) + deg;
4338    cache.rotationX = _round(rotationX) + deg;
4339    cache.rotationY = _round(rotationY) + deg;
vendor: 4,199 bytes, lines 4340-4467
4340    cache.skewX = skewX + deg;
4341    cache.skewY = skewY + deg;
4342    cache.transformPerspective = perspective + px;
4343
4344    if (cache.zOrigin = parseFloat(origin.split(" ")[2]) || 0) {
4345      style[_transformOriginProp] = _firstTwoOnly(origin);
4346    }
4347
4348    cache.xOffset = cache.yOffset = 0;
4349    cache.force3D = _config.force3D;
4350    cache.renderTransform = cache.svg ? _renderSVGTransforms : _supports3D ? _renderCSSTransforms : _renderNon3DTransforms;
4351    cache.uncache = 0;
4352    return cache;
4353  },
4354      _firstTwoOnly = function _firstTwoOnly(value) {
4355    return (value = value.split(" "))[0] + " " + value[1];
4356  },
4357      _addPxTranslate = function _addPxTranslate(target, start, value) {
4358    var unit = getUnit(start);
4359    return _round(parseFloat(start) + parseFloat(_convertToUnit(target, "x", value + "px", unit))) + unit;
4360  },
4361      _renderNon3DTransforms = function _renderNon3DTransforms(ratio, cache) {
4362    cache.z = "0px";
4363    cache.rotationY = cache.rotationX = "0deg";
4364    cache.force3D = 0;
4365
4366    _renderCSSTransforms(ratio, cache);
4367  },
4368      _zeroDeg = "0deg",
4369      _zeroPx = "0px",
4370      _endParenthesis = ") ",
4371      _renderCSSTransforms = function _renderCSSTransforms(ratio, cache) {
4372    var _ref = cache || this,
4373        xPercent = _ref.xPercent,
4374        yPercent = _ref.yPercent,
4375        x = _ref.x,
4376        y = _ref.y,
4377        z = _ref.z,
4378        rotation = _ref.rotation,
4379        rotationY = _ref.rotationY,
4380        rotationX = _ref.rotationX,
4381        skewX = _ref.skewX,
4382        skewY = _ref.skewY,
4383        scaleX = _ref.scaleX,
4384        scaleY = _ref.scaleY,
4385        transformPerspective = _ref.transformPerspective,
4386        force3D = _ref.force3D,
4387        target = _ref.target,
4388        zOrigin = _ref.zOrigin,
4389        transforms = "",
4390        use3D = force3D === "auto" && ratio && ratio !== 1 || force3D === true;
4391
4392    if (zOrigin && (rotationX !== _zeroDeg || rotationY !== _zeroDeg)) {
4393      var angle = parseFloat(rotationY) * _DEG2RAD,
4394          a13 = Math.sin(angle),
4395          a33 = Math.cos(angle),
4396          cos;
4397
4398      angle = parseFloat(rotationX) * _DEG2RAD;
4399      cos = Math.cos(angle);
4400      x = _addPxTranslate(target, x, a13 * cos * -zOrigin);
4401      y = _addPxTranslate(target, y, -Math.sin(angle) * -zOrigin);
4402      z = _addPxTranslate(target, z, a33 * cos * -zOrigin + zOrigin);
4403    }
4404
4405    if (transformPerspective !== _zeroPx) {
4406      transforms += "perspective(" + transformPerspective + _endParenthesis;
4407    }
4408
4409    if (xPercent || yPercent) {
4410      transforms += "translate(" + xPercent + "%, " + yPercent + "%) ";
4411    }
4412
4413    if (use3D || x !== _zeroPx || y !== _zeroPx || z !== _zeroPx) {
4414      transforms += z !== _zeroPx || use3D ? "translate3d(" + x + ", " + y + ", " + z + ") " : "translate(" + x + ", " + y + _endParenthesis;
4415    }
4416
4417    if (rotation !== _zeroDeg) {
4418      transforms += "rotate(" + rotation + _endParenthesis;
4419    }
4420
4421    if (rotationY !== _zeroDeg) {
4422      transforms += "rotateY(" + rotationY + _endParenthesis;
4423    }
4424
4425    if (rotationX !== _zeroDeg) {
4426      transforms += "rotateX(" + rotationX + _endParenthesis;
4427    }
4428
4429    if (skewX !== _zeroDeg || skewY !== _zeroDeg) {
4430      transforms += "skew(" + skewX + ", " + skewY + _endParenthesis;
4431    }
4432
4433    if (scaleX !== 1 || scaleY !== 1) {
4434      transforms += "scale(" + scaleX + ", " + scaleY + _endParenthesis;
4435    }
4436
4437    target.style[_transformProp] = transforms || "translate(0, 0)";
4438  },
4439      _renderSVGTransforms = function _renderSVGTransforms(ratio, cache) {
4440    var _ref2 = cache || this,
4441        xPercent = _ref2.xPercent,
4442        yPercent = _ref2.yPercent,
4443        x = _ref2.x,
4444        y = _ref2.y,
4445        rotation = _ref2.rotation,
4446        skewX = _ref2.skewX,
4447        skewY = _ref2.skewY,
4448        scaleX = _ref2.scaleX,
4449        scaleY = _ref2.scaleY,
4450        target = _ref2.target,
4451        xOrigin = _ref2.xOrigin,
4452        yOrigin = _ref2.yOrigin,
4453        xOffset = _ref2.xOffset,
4454        yOffset = _ref2.yOffset,
4455        forceCSS = _ref2.forceCSS,
4456        tx = parseFloat(x),
4457        ty = parseFloat(y),
4458        a11,
4459        a21,
4460        a12,
4461        a22,
4462        temp;
4463
4464    rotation = parseFloat(rotation);
4465    skewX = parseFloat(skewX);
4466    skewY = parseFloat(skewY);
4467
vendor: 4,432 bytes, lines 4468-4616
4468    if (skewY) {
4469      skewY = parseFloat(skewY);
4470      skewX += skewY;
4471      rotation += skewY;
4472    }
4473
4474    if (rotation || skewX) {
4475      rotation *= _DEG2RAD;
4476      skewX *= _DEG2RAD;
4477      a11 = Math.cos(rotation) * scaleX;
4478      a21 = Math.sin(rotation) * scaleX;
4479      a12 = Math.sin(rotation - skewX) * -scaleY;
4480      a22 = Math.cos(rotation - skewX) * scaleY;
4481
4482      if (skewX) {
4483        skewY *= _DEG2RAD;
4484        temp = Math.tan(skewX - skewY);
4485        temp = Math.sqrt(1 + temp * temp);
4486        a12 *= temp;
4487        a22 *= temp;
4488
4489        if (skewY) {
4490          temp = Math.tan(skewY);
4491          temp = Math.sqrt(1 + temp * temp);
4492          a11 *= temp;
4493          a21 *= temp;
4494        }
4495      }
4496
4497      a11 = _round(a11);
4498      a21 = _round(a21);
4499      a12 = _round(a12);
4500      a22 = _round(a22);
4501    } else {
4502      a11 = scaleX;
4503      a22 = scaleY;
4504      a21 = a12 = 0;
4505    }
4506
4507    if (tx && !~(x + "").indexOf("px") || ty && !~(y + "").indexOf("px")) {
4508      tx = _convertToUnit(target, "x", x, "px");
4509      ty = _convertToUnit(target, "y", y, "px");
4510    }
4511
4512    if (xOrigin || yOrigin || xOffset || yOffset) {
4513      tx = _round(tx + xOrigin - (xOrigin * a11 + yOrigin * a12) + xOffset);
4514      ty = _round(ty + yOrigin - (xOrigin * a21 + yOrigin * a22) + yOffset);
4515    }
4516
4517    if (xPercent || yPercent) {
4518      temp = target.getBBox();
4519      tx = _round(tx + xPercent / 100 * temp.width);
4520      ty = _round(ty + yPercent / 100 * temp.height);
4521    }
4522
4523    temp = "matrix(" + a11 + "," + a21 + "," + a12 + "," + a22 + "," + tx + "," + ty + ")";
4524    target.setAttribute("transform", temp);
4525    forceCSS && (target.style[_transformProp] = temp);
4526  },
4527      _addRotationalPropTween = function _addRotationalPropTween(plugin, target, property, startNum, endValue, relative) {
4528    var cap = 360,
4529        isString = _isString(endValue),
4530        endNum = parseFloat(endValue) * (isString && ~endValue.indexOf("rad") ? _RAD2DEG : 1),
4531        change = relative ? endNum * relative : endNum - startNum,
4532        finalValue = startNum + change + "deg",
4533        direction,
4534        pt;
4535
4536    if (isString) {
4537      direction = endValue.split("_")[1];
4538
4539      if (direction === "short") {
4540        change %= cap;
4541
4542        if (change !== change % (cap / 2)) {
4543          change += change < 0 ? cap : -cap;
4544        }
4545      }
4546
4547      if (direction === "cw" && change < 0) {
4548        change = (change + cap * _bigNum$1) % cap - ~~(change / cap) * cap;
4549      } else if (direction === "ccw" && change > 0) {
4550        change = (change - cap * _bigNum$1) % cap - ~~(change / cap) * cap;
4551      }
4552    }
4553
4554    plugin._pt = pt = new PropTween(plugin._pt, target, property, startNum, change, _renderPropWithEnd);
4555    pt.e = finalValue;
4556    pt.u = "deg";
4557
4558    plugin._props.push(property);
4559
4560    return pt;
4561  },
4562      _assign = function _assign(target, source) {
4563    for (var p in source) {
4564      target[p] = source[p];
4565    }
4566
4567    return target;
4568  },
4569      _addRawTransformPTs = function _addRawTransformPTs(plugin, transforms, target) {
4570    var startCache = _assign({}, target._gsap),
4571        exclude = "perspective,force3D,transformOrigin,svgOrigin",
4572        style = target.style,
4573        endCache,
4574        p,
4575        startValue,
4576        endValue,
4577        startNum,
4578        endNum,
4579        startUnit,
4580        endUnit;
4581
4582    if (startCache.svg) {
4583      startValue = target.getAttribute("transform");
4584      target.setAttribute("transform", "");
4585      style[_transformProp] = transforms;
4586      endCache = _parseTransform(target, 1);
4587
4588      _removeProperty(target, _transformProp);
4589
4590      target.setAttribute("transform", startValue);
4591    } else {
4592      startValue = getComputedStyle(target)[_transformProp];
4593      style[_transformProp] = transforms;
4594      endCache = _parseTransform(target, 1);
4595      style[_transformProp] = startValue;
4596    }
4597
4598    for (p in _transformProps) {
4599      startValue = startCache[p];
4600      endValue = endCache[p];
4601
4602      if (startValue !== endValue && exclude.indexOf(p) < 0) {
4603        startUnit = getUnit(startValue);
4604        endUnit = getUnit(endValue);
4605        startNum = startUnit !== endUnit ? _convertToUnit(target, p, startValue, endUnit) : parseFloat(startValue);
4606        endNum = parseFloat(endValue);
4607        plugin._pt = new PropTween(plugin._pt, endCache, p, startNum, endNum - startNum, _renderCSSProp);
4608        plugin._pt.u = endUnit || 0;
4609
4610        plugin._props.push(p);
4611      }
4612    }
4613
4614    _assign(endCache, startCache);
4615  };
4616
vendor: 4,076 bytes, lines 4617-4738
4617  _forEachName("padding,margin,Width,Radius", function (name, index) {
4618    var t = "Top",
4619        r = "Right",
4620        b = "Bottom",
4621        l = "Left",
4622        props = (index < 3 ? [t, r, b, l] : [t + l, t + r, b + r, b + l]).map(function (side) {
4623      return index < 2 ? name + side : "border" + side + name;
4624    });
4625
4626    _specialProps[index > 1 ? "border" + name : name] = function (plugin, target, property, endValue, tween) {
4627      var a, vars;
4628
4629      if (arguments.length < 4) {
4630        a = props.map(function (prop) {
4631          return _get(plugin, prop, property);
4632        });
4633        vars = a.join(" ");
4634        return vars.split(a[0]).length === 5 ? a[0] : vars;
4635      }
4636
4637      a = (endValue + "").split(" ");
4638      vars = {};
4639      props.forEach(function (prop, i) {
4640        return vars[prop] = a[i] = a[i] || a[(i - 1) / 2 | 0];
4641      });
4642      plugin.init(target, vars, tween);
4643    };
4644  });
4645
4646  var CSSPlugin = {
4647    name: "css",
4648    register: _initCore,
4649    targetTest: function targetTest(target) {
4650      return target.style && target.nodeType;
4651    },
4652    init: function init(target, vars, tween, index, targets) {
4653      var props = this._props,
4654          style = target.style,
4655          startAt = tween.vars.startAt,
4656          startValue,
4657          endValue,
4658          endNum,
4659          startNum,
4660          type,
4661          specialProp,
4662          p,
4663          startUnit,
4664          endUnit,
4665          relative,
4666          isTransformRelated,
4667          transformPropTween,
4668          cache,
4669          smooth,
4670          hasPriority;
4671      _pluginInitted || _initCore();
4672
4673      for (p in vars) {
4674        if (p === "autoRound") {
4675          continue;
4676        }
4677
4678        endValue = vars[p];
4679
4680        if (_plugins[p] && _checkPlugin(p, vars, tween, index, target, targets)) {
4681          continue;
4682        }
4683
4684        type = typeof endValue;
4685        specialProp = _specialProps[p];
4686
4687        if (type === "function") {
4688          endValue = endValue.call(tween, index, target, targets);
4689          type = typeof endValue;
4690        }
4691
4692        if (type === "string" && ~endValue.indexOf("random(")) {
4693          endValue = _replaceRandom(endValue);
4694        }
4695
4696        if (specialProp) {
4697          specialProp(this, target, p, endValue, tween) && (hasPriority = 1);
4698        } else if (p.substr(0, 2) === "--") {
4699          startValue = (getComputedStyle(target).getPropertyValue(p) + "").trim();
4700          endValue += "";
4701          _colorExp.lastIndex = 0;
4702
4703          if (!_colorExp.test(startValue)) {
4704            startUnit = getUnit(startValue);
4705            endUnit = getUnit(endValue);
4706          }
4707
4708          endUnit ? startUnit !== endUnit && (startValue = _convertToUnit(target, p, startValue, endUnit) + endUnit) : startUnit && (endValue += startUnit);
4709          this.add(style, "setProperty", startValue, endValue, index, targets, 0, 0, p);
4710        } else if (type !== "undefined") {
4711          if (startAt && p in startAt) {
4712            startValue = typeof startAt[p] === "function" ? startAt[p].call(tween, index, target, targets) : startAt[p];
4713            p in _config.units && !getUnit(startValue) && (startValue += _config.units[p]);
4714            (startValue + "").charAt(1) === "=" && (startValue = _get(target, p));
4715          } else {
4716            startValue = _get(target, p);
4717          }
4718
4719          startNum = parseFloat(startValue);
4720          relative = type === "string" && endValue.charAt(1) === "=" ? +(endValue.charAt(0) + "1") : 0;
4721          relative && (endValue = endValue.substr(2));
4722          endNum = parseFloat(endValue);
4723
4724          if (p in _propertyAliases) {
4725            if (p === "autoAlpha") {
4726              if (startNum === 1 && _get(target, "visibility") === "hidden" && endNum) {
4727                startNum = 0;
4728              }
4729
4730              _addNonTweeningPT(this, style, "visibility", startNum ? "inherit" : "hidden", endNum ? "inherit" : "hidden", !endNum);
4731            }
4732
4733            if (p !== "scale" && p !== "transform") {
4734              p = _propertyAliases[p];
4735              ~p.indexOf(",") && (p = p.split(",")[0]);
4736            }
4737          }
4738
vendor: 4,279 bytes, lines 4739-4832
4739          isTransformRelated = p in _transformProps;
4740
4741          if (isTransformRelated) {
4742            if (!transformPropTween) {
4743              cache = target._gsap;
4744              cache.renderTransform && !vars.parseTransform || _parseTransform(target, vars.parseTransform);
4745              smooth = vars.smoothOrigin !== false && cache.smooth;
4746              transformPropTween = this._pt = new PropTween(this._pt, style, _transformProp, 0, 1, cache.renderTransform, cache, 0, -1);
4747              transformPropTween.dep = 1;
4748            }
4749
4750            if (p === "scale") {
4751              this._pt = new PropTween(this._pt, cache, "scaleY", cache.scaleY, relative ? relative * endNum : endNum - cache.scaleY);
4752              props.push("scaleY", p);
4753              p += "X";
4754            } else if (p === "transformOrigin") {
4755              endValue = _convertKeywordsToPercentages(endValue);
4756
4757              if (cache.svg) {
4758                _applySVGOrigin(target, endValue, 0, smooth, 0, this);
4759              } else {
4760                endUnit = parseFloat(endValue.split(" ")[2]) || 0;
4761                endUnit !== cache.zOrigin && _addNonTweeningPT(this, cache, "zOrigin", cache.zOrigin, endUnit);
4762
4763                _addNonTweeningPT(this, style, p, _firstTwoOnly(startValue), _firstTwoOnly(endValue));
4764              }
4765
4766              continue;
4767            } else if (p === "svgOrigin") {
4768              _applySVGOrigin(target, endValue, 1, smooth, 0, this);
4769
4770              continue;
4771            } else if (p in _rotationalProperties) {
4772              _addRotationalPropTween(this, cache, p, startNum, endValue, relative);
4773
4774              continue;
4775            } else if (p === "smoothOrigin") {
4776              _addNonTweeningPT(this, cache, "smooth", cache.smooth, endValue);
4777
4778              continue;
4779            } else if (p === "force3D") {
4780              cache[p] = endValue;
4781              continue;
4782            } else if (p === "transform") {
4783              _addRawTransformPTs(this, endValue, target);
4784
4785              continue;
4786            }
4787          } else if (!(p in style)) {
4788            p = _checkPropPrefix(p) || p;
4789          }
4790
4791          if (isTransformRelated || (endNum || endNum === 0) && (startNum || startNum === 0) && !_complexExp.test(endValue) && p in style) {
4792            startUnit = (startValue + "").substr((startNum + "").length);
4793            endNum || (endNum = 0);
4794            endUnit = getUnit(endValue) || (p in _config.units ? _config.units[p] : startUnit);
4795            startUnit !== endUnit && (startNum = _convertToUnit(target, p, startValue, endUnit));
4796            this._pt = new PropTween(this._pt, isTransformRelated ? cache : style, p, startNum, relative ? relative * endNum : endNum - startNum, !isTransformRelated && (endUnit === "px" || p === "zIndex") && vars.autoRound !== false ? _renderRoundedCSSProp : _renderCSSProp);
4797            this._pt.u = endUnit || 0;
4798
4799            if (startUnit !== endUnit) {
4800              this._pt.b = startValue;
4801              this._pt.r = _renderCSSPropWithBeginning;
4802            }
4803          } else if (!(p in style)) {
4804            if (p in target) {
4805              this.add(target, p, target[p], endValue, index, targets);
4806            } else {
4807              _missingPlugin(p, endValue);
4808
4809              continue;
4810            }
4811          } else {
4812            _tweenComplexCSSString.call(this, target, p, startValue, endValue);
4813          }
4814
4815          props.push(p);
4816        }
4817      }
4818
4819      hasPriority && _sortPropTweensByPriority(this);
4820    },
4821    get: _get,
4822    aliases: _propertyAliases,
4823    getSetter: function getSetter(target, property, plugin) {
4824      var p = _propertyAliases[property];
4825      p && p.indexOf(",") < 0 && (property = p);
4826      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);
4827    },
4828    core: {
4829      _removeProperty: _removeProperty,
4830      _getMatrix: _getMatrix
4831    }
4832  };
4833  gsap.utils.checkPrefix = _checkPropPrefix;
4834
4835  (function (positionAndScale, rotation, others, aliases) {
4836    var all = _forEachName(positionAndScale + "," + rotation + "," + others, function (name) {
4837      _transformProps[name] = 1;
4838    });
4839
4840    _forEachName(rotation, function (name) {
4841      _config.units[name] = "deg";
4842      _rotationalProperties[name] = 1;
4843    });
4844
4845    _propertyAliases[all[13]] = positionAndScale + "," + rotation;
4846
4847    _forEachName(aliases, function (name) {
4848      var split = name.split(":");
4849      _propertyAliases[split[1]] = all[split[0]];
4850    });
4851  })("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");
4852
4853  _forEachName("x,y,z,top,right,bottom,left,width,height,fontSize,padding,margin,perspective", function (name) {
4854    _config.units[name] = "px";
4855  });
4856
4857  gsap.registerPlugin(CSSPlugin);
4858
4859  var gsapWithCSS = gsap.registerPlugin(CSSPlugin) || gsap,
4860      TweenMaxWithCSS = gsapWithCSS.core.Tween;
4861
4862  exports.Back = Back;
4863  exports.Bounce = Bounce;
4864  exports.CSSPlugin = CSSPlugin;
4865  exports.Circ = Circ;
4866  exports.Cubic = Cubic;
4867  exports.Elastic = Elastic;
4868  exports.Expo = Expo;
4869  exports.Linear = Linear;
4870  exports.Power0 = Power0;
4871  exports.Power1 = Power1;
4872  exports.Power2 = Power2;
4873  exports.Power3 = Power3;
4874  exports.Power4 = Power4;
4875  exports.Quad = Quad;
4876  exports.Quart = Quart;
4877  exports.Quint = Quint;
4878  exports.Sine = Sine;
4879  exports.SteppedEase = SteppedEase;
4880  exports.Strong = Strong;
4881  exports.TimelineLite = Timeline;
4882  exports.TimelineMax = Timeline;
4883  exports.TweenLite = Tween;
4884  exports.TweenMax = TweenMaxWithCSS;
4885  exports.default = gsapWithCSS;
4886  exports.gsap = gsapWithCSS;
4887
4888  if (typeof(window) === 'undefined' || window !== exports) {Object.defineProperty(exports, '__esModule', { value: true });} else {delete window.default;}
4889
4890})));
4891
4892(function(window, $) {
4893  'use strict';
4894  var counter = 0,
4895    $headCache = $('head'),
4896    oldBigText = window.BigText,
4897    oldjQueryMethod = $.fn.bigtext,
4898    BigText = {
4899      DEBUG_MODE: false,
4900      DEFAULT_MIN_FONT_SIZE_PX: null,
4901      DEFAULT_MAX_FONT_SIZE_PX: 528,
4902      GLOBAL_STYLE_ID: 'bigtext-style',
4903      STYLE_ID: 'bigtext-id',
4904      LINE_CLASS_PREFIX: 'bigtext-line',
4905      EXEMPT_CLASS: 'bigtext-exempt',
4906      noConflict: function(restore)
4907      {
4908        if(restore) {
4909          $.fn.bigtext = oldjQueryMethod;
4910          window.BigText = oldBigText;
4911        }
4912        return BigText;
4913      },
4914      supports: {
4915        wholeNumberFontSizeOnly: (function() {
4916          if( !( 'getComputedStyle' in window ) ) {
4917            return true;
4918          }
4919          var test = $('<div/>').css({
4920              position: 'absolute',
4921              'font-size': '14.1px'
4922            }).insertBefore( $('script').eq(0) ),
4923            computedStyle = window.getComputedStyle( test[0], null );
4924
4925          var ret = computedStyle && computedStyle.getPropertyValue( 'font-size' ) === '14px';
4926          test.remove();
4927          return ret;
4928        })()
4929      },
4930      init: function() {
4931        if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
4932          $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; } .bigtext > * { display: block; }',
4933                                          '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
4934        }
4935      },
4936      bindResize: function(eventName, resizeFunction) {
4937        var timeoutId;
4938        $(window).unbind(eventName).bind(eventName, function() {
4939          if( timeoutId ) {
4940            clearTimeout( timeoutId );
4941          }
4942          timeoutId = setTimeout( resizeFunction, 300 );
4943        });
4944      },
4945      getStyleId: function(id)
4946      {
4947        return BigText.STYLE_ID + '-' + id;
4948      },
4949      generateStyleTag: function(id, css)
4950      {
4951        return $('<style>' + css.join('\n') + '</style>').attr('id', id);
4952      },
4953      clearCss: function(id)
4954      {
4955        var styleId = BigText.getStyleId(id);
4956        $('#' + styleId).remove();
4957      },
4958      generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
4959      {
4960        var css = [];
4961
4962        BigText.clearCss(id);
4963
4964        for(var j=0, k=linesFontSizes.length; j<k; j++) {
4965          css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
4966            (minFontSizes[j] ? ' white-space: normal;' : '') +
4967            (linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
4968            (lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
4969            '}');
4970        }
4971
4972        return BigText.generateStyleTag(BigText.getStyleId(id), css);
4973      },
4974      jQueryMethod: function(options)
4975      {
4976        BigText.init();
4977
4978        options = $.extend({
4979          minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
4980          maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
4981          childSelector: '',
4982          resize: true
4983        }, options || {});
4984
4985        this.each(function()
4986        {
4987          var $t = $(this).addClass('bigtext'),
4988            maxWidth = $t.width(),
4989            id = $t.attr('id'),
4990            $children = options.childSelector ? $t.find( options.childSelector ) : $t.children();
4991
4992          if(!id) {
4993            id = 'bigtext-id' + (counter++);
4994            $t.attr('id', id);
4995          }
4996
4997          if(options.resize) {
4998            BigText.bindResize('resize.bigtext-event-' + id, function()
4999            {
5000              // TODO only call this if the width has changed.
5001              BigText.jQueryMethod.call($('#' + id), options);
5002            });
5003          }
5004
5005          BigText.clearCss(id);
5006
5007          $children.addClass(function(lineNumber, className)
5008          {
5009            // remove existing line classes.
5010            return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
5011                BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
5012          });
5013
5014          var sizes = calculateSizes($t, $children, maxWidth, options.maxfontsize, options.minfontsize);
5015          $headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
5016        });
5017
5018        return this.trigger('bigtext:complete');
5019      }
5020    };
5021
5022  function testLineDimensions($line, maxWidth, property, size, interval, units, previousWidth)
5023  {
5024    var width;
5025    previousWidth = typeof previousWidth === 'number' ? previousWidth : 0;
5026    $line.css(property, size + units);
5027
5028    width = $line.width();
5029
5030    if(width >= maxWidth) {
5031
5032      $line.css(property, '');
5033
5034      if(width === maxWidth) {
5035        return {
5036          match: 'exact',
5037          size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
5038        };
5039      }
5040
5041      // Since this is an estimate, we calculate how far over the width we went with the new value.
5042      // If this is word-spacing (our last resort guess) and the over is less than the under, we keep the higher value.
5043      // Otherwise, we revert to the underestimate.
5044      var under = maxWidth - previousWidth,
5045        over = width - maxWidth;
5046
5047      return {
5048        match: 'estimate',
5049        size: parseFloat((parseFloat(size) - (property === 'word-spacing' && previousWidth && ( over < under ) ? 0 : interval)).toFixed(3))
5050      };
5051    }
5052
5053    return width;
5054  }
5055
5056  function calculateSizes($t, $children, maxWidth, maxFontSize, minFontSize)
5057  {
5058    var $c = $t.clone(true)
5059      .addClass('bigtext-cloned')
5060      .css({
5061        fontFamily: $t.css('font-family'),
5062        textTransform: $t.css('text-transform'),
5063        wordSpacing: $t.css('word-spacing'),
5064        letterSpacing: $t.css('letter-spacing'),
5065        position: 'absolute',
5066        left: BigText.DEBUG_MODE ? 0 : -9999,
5067        top: BigText.DEBUG_MODE ? 0 : -9999
5068      })
5069      .appendTo(document.body);
5070
5071    // font-size isn't the only thing we can modify, we can also mess with:
5072    // word-spacing and letter-spacing. WebKit does not respect subpixel
5073    // letter-spacing, word-spacing, or font-size.
5074    // TODO try -webkit-transform: scale() as a workaround.
5075    var fontSizes = [],
5076      wordSpacings = [],
5077      minFontSizes = [],
5078      ratios = [];
5079
5080    $children.css('float', 'left').each(function() {
5081      var $line = $(this),
5082        // TODO replace 8, 4 with a proportional size to the calculated font-size.
5083        intervals = BigText.supports.wholeNumberFontSizeOnly ? [8, 4, 1] : [8, 4, 1, 0.1],
5084        lineMax,
5085        newFontSize;
5086
5087      if($line.hasClass(BigText.EXEMPT_CLASS)) {
5088        fontSizes.push(null);
5089        ratios.push(null);
5090        minFontSizes.push(false);
5091        return;
5092      }
5093
5094      // TODO we can cache this ratio?
5095      var autoGuessSubtraction = 32, // font size in px
5096        currentFontSize = parseFloat($line.css('font-size')),
5097        ratio = ( $line.width() / currentFontSize ).toFixed(6);
5098
5099      newFontSize = parseInt( maxWidth / ratio, 10 ) - autoGuessSubtraction;
5100
5101      outer: for(var m=0, n=intervals.length; m<n; m++) {
5102        inner: for(var j=1, k=10; j<=k; j++) {
5103          if(newFontSize + j*intervals[m] > maxFontSize) {
5104            newFontSize = maxFontSize;
5105            break outer;
5106          }
5107
5108          lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px', lineMax);
5109          if(typeof lineMax !== 'number') {
5110            newFontSize = lineMax.size;
5111
5112            if(lineMax.match === 'exact') {
5113              break outer;
5114            }
5115            break inner;
5116          }
5117        }
5118      }
5119
5120      ratios.push(maxWidth / newFontSize);
5121
5122      if(newFontSize > maxFontSize) {
5123        fontSizes.push(maxFontSize);
5124        minFontSizes.push(false);
5125      } else if(!!minFontSize && newFontSize < minFontSize) {
5126        fontSizes.push(minFontSize);
5127        minFontSizes.push(true);
5128      } else {
5129        fontSizes.push(newFontSize);
5130        minFontSizes.push(false);
5131      }
5132    }).each(function(lineNumber) {
5133      var $line = $(this),
5134        wordSpacing = 0,
5135        interval = 1,
5136        maxWordSpacing;
5137
5138      if($line.hasClass(BigText.EXEMPT_CLASS)) {
5139        wordSpacings.push(null);
5140        return;
5141      }
5142
5143      // must re-use font-size, even though it was removed above.
5144      $line.css('font-size', fontSizes[lineNumber] + 'px');
5145
5146      for(var m=1, n=3; m<n; m+=interval) {
5147        maxWordSpacing = testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px', maxWordSpacing);
5148        if(typeof maxWordSpacing !== 'number') {
5149          wordSpacing = maxWordSpacing.size;
5150          break;
5151        }
5152      }
5153
5154      $line.css('font-size', '');
5155      wordSpacings.push(wordSpacing);
5156    }).removeAttr('style');
5157
5158    if( !BigText.DEBUG_MODE ) {
5159      $c.remove();
5160    } else {
5161      $c.css({
5162        'background-color': 'rgba(255,255,255,.4)'
5163      });
5164    }
5165
5166    return {
5167      fontSizes: fontSizes,
5168      wordSpacings: wordSpacings,
5169      ratios: ratios,
5170      minFontSizes: minFontSizes
5171    };
5172  }
5173
5174  $.fn.bigtext = BigText.jQueryMethod;
5175  window.BigText = BigText;
5176
5177})(this, jQuery);
5178/*!
5179 * Isotope PACKAGED v3.0.6
5180 *
5181 * Licensed GPLv3 for open source use
5182 * or Isotope Commercial License for commercial use
5183 *
5184 * https://isotope.metafizzy.co
5185 * Copyright 2010-2018 Metafizzy
vendor: 15,902 bytes, lines 5185-5835
5185
5186 */
5187
5188/**
5189 * Bridget makes jQuery widgets
5190 * v2.0.1
5191 * MIT license
5192 */
5193
5194/* jshint browser: true, strict: true, undef: true, unused: true */
5195
5196( function( window, factory ) {
5197  // universal module definition
5198  /*jshint strict: false */ /* globals define, module, require */
5199  if ( typeof define == 'function' && define.amd ) {
5200    // AMD
5201    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
5202      return factory( window, jQuery );
5203    });
5204  } else if ( typeof module == 'object' && module.exports ) {
5205    // CommonJS
5206    module.exports = factory(
5207      window,
5208      require('jquery')
5209    );
5210  } else {
5211    // browser global
5212    window.jQueryBridget = factory(
5213      window,
5214      window.jQuery
5215    );
5216  }
5217
5218}( window, function factory( window, jQuery ) {
5219'use strict';
5220
5221// ----- utils ----- //
5222
5223var arraySlice = Array.prototype.slice;
5224
5225// helper function for logging errors
5226// $.error breaks jQuery chaining
5227var console = window.console;
5228var logError = typeof console == 'undefined' ? function() {} :
5229  function( message ) {
5230    console.error( message );
5231  };
5232
5233// ----- jQueryBridget ----- //
5234
5235function jQueryBridget( namespace, PluginClass, $ ) {
5236  $ = $ || jQuery || window.jQuery;
5237  if ( !$ ) {
5238    return;
5239  }
5240
5241  // add option method -> $().plugin('option', {...})
5242  if ( !PluginClass.prototype.option ) {
5243    // option setter
5244    PluginClass.prototype.option = function( opts ) {
5245      // bail out if not an object
5246      if ( !$.isPlainObject( opts ) ){
5247        return;
5248      }
5249      this.options = $.extend( true, this.options, opts );
5250    };
5251  }
5252
5253  // make jQuery plugin
5254  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
5255    if ( typeof arg0 == 'string' ) {
5256      // method call $().plugin( 'methodName', { options } )
5257      // shift arguments by 1
5258      var args = arraySlice.call( arguments, 1 );
5259      return methodCall( this, arg0, args );
5260    }
5261    // just $().plugin({ options })
5262    plainCall( this, arg0 );
5263    return this;
5264  };
5265
5266  // $().plugin('methodName')
5267  function methodCall( $elems, methodName, args ) {
5268    var returnValue;
5269    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
5270
5271    $elems.each( function( i, elem ) {
5272      // get instance
5273      var instance = $.data( elem, namespace );
5274      if ( !instance ) {
5275        logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
5276          pluginMethodStr );
5277        return;
5278      }
5279
5280      var method = instance[ methodName ];
5281      if ( !method || methodName.charAt(0) == '_' ) {
5282        logError( pluginMethodStr + ' is not a valid method' );
5283        return;
5284      }
5285
5286      // apply method, get return value
5287      var value = method.apply( instance, args );
5288      // set return value if value is returned, use only first value
5289      returnValue = returnValue === undefined ? value : returnValue;
5290    });
5291
5292    return returnValue !== undefined ? returnValue : $elems;
5293  }
5294
5295  function plainCall( $elems, options ) {
5296    $elems.each( function( i, elem ) {
5297      var instance = $.data( elem, namespace );
5298      if ( instance ) {
5299        // set options & init
5300        instance.option( options );
5301        instance._init();
5302      } else {
5303        // initialize new instance
5304        instance = new PluginClass( elem, options );
5305        $.data( elem, namespace, instance );
5306      }
5307    });
5308  }
5309
5310  updateJQuery( $ );
5311
5312}
5313
5314// ----- updateJQuery ----- //
5315
5316// set $.bridget for v1 backwards compatibility
5317function updateJQuery( $ ) {
5318  if ( !$ || ( $ && $.bridget ) ) {
5319    return;
5320  }
5321  $.bridget = jQueryBridget;
5322}
5323
5324updateJQuery( jQuery || window.jQuery );
5325
5326// -----  ----- //
5327
5328return jQueryBridget;
5329
5330}));
5331
5332/**
5333 * EvEmitter v1.1.0
5334 * Lil' event emitter
5335 * MIT License
5336 */
5337
5338/* jshint unused: true, undef: true, strict: true */
5339
5340( function( global, factory ) {
5341  // universal module definition
5342  /* jshint strict: false */ /* globals define, module, window */
5343  if ( typeof define == 'function' && define.amd ) {
5344    // AMD - RequireJS
5345    define( 'ev-emitter/ev-emitter',factory );
5346  } else if ( typeof module == 'object' && module.exports ) {
5347    // CommonJS - Browserify, Webpack
5348    module.exports = factory();
5349  } else {
5350    // Browser globals
5351    global.EvEmitter = factory();
5352  }
5353
5354}( typeof window != 'undefined' ? window : this, function() {
5355
5356
5357
5358function EvEmitter() {}
5359
5360var proto = EvEmitter.prototype;
5361
5362proto.on = function( eventName, listener ) {
5363  if ( !eventName || !listener ) {
5364    return;
5365  }
5366  // set events hash
5367  var events = this._events = this._events || {};
5368  // set listeners array
5369  var listeners = events[ eventName ] = events[ eventName ] || [];
5370  // only add once
5371  if ( listeners.indexOf( listener ) == -1 ) {
5372    listeners.push( listener );
5373  }
5374
5375  return this;
5376};
5377
5378proto.once = function( eventName, listener ) {
5379  if ( !eventName || !listener ) {
5380    return;
5381  }
5382  // add event
5383  this.on( eventName, listener );
5384  // set once flag
5385  // set onceEvents hash
5386  var onceEvents = this._onceEvents = this._onceEvents || {};
5387  // set onceListeners object
5388  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
5389  // set flag
5390  onceListeners[ listener ] = true;
5391
5392  return this;
5393};
5394
5395proto.off = function( eventName, listener ) {
5396  var listeners = this._events && this._events[ eventName ];
5397  if ( !listeners || !listeners.length ) {
5398    return;
5399  }
5400  var index = listeners.indexOf( listener );
5401  if ( index != -1 ) {
5402    listeners.splice( index, 1 );
5403  }
5404
5405  return this;
5406};
5407
5408proto.emitEvent = function( eventName, args ) {
5409  var listeners = this._events && this._events[ eventName ];
5410  if ( !listeners || !listeners.length ) {
5411    return;
5412  }
5413  // copy over to avoid interference if .off() in listener
5414  listeners = listeners.slice(0);
5415  args = args || [];
5416  // once stuff
5417  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
5418
5419  for ( var i=0; i < listeners.length; i++ ) {
5420    var listener = listeners[i]
5421    var isOnce = onceListeners && onceListeners[ listener ];
5422    if ( isOnce ) {
5423      // remove listener
5424      // remove before trigger to prevent recursion
5425      this.off( eventName, listener );
5426      // unset once flag
5427      delete onceListeners[ listener ];
5428    }
5429    // trigger listener
5430    listener.apply( this, args );
5431  }
5432
5433  return this;
5434};
5435
5436proto.allOff = function() {
5437  delete this._events;
5438  delete this._onceEvents;
5439};
5440
5441return EvEmitter;
5442
5443}));
5444
5445/*!
5446 * getSize v2.0.3
5447 * measure size of elements
5448 * MIT license
5449 */
5450
5451/* jshint browser: true, strict: true, undef: true, unused: true */
5452/* globals console: false */
5453
5454( function( window, factory ) {
5455  /* jshint strict: false */ /* globals define, module */
5456  if ( typeof define == 'function' && define.amd ) {
5457    // AMD
5458    define( 'get-size/get-size',factory );
5459  } else if ( typeof module == 'object' && module.exports ) {
5460    // CommonJS
5461    module.exports = factory();
5462  } else {
5463    // browser global
5464    window.getSize = factory();
5465  }
5466
5467})( window, function factory() {
5468'use strict';
5469
5470// -------------------------- helpers -------------------------- //
5471
5472// get a number from a string, not a percentage
5473function getStyleSize( value ) {
5474  var num = parseFloat( value );
5475  // not a percent like '100%', and a number
5476  var isValid = value.indexOf('%') == -1 && !isNaN( num );
5477  return isValid && num;
5478}
5479
5480function noop() {}
5481
5482var logError = typeof console == 'undefined' ? noop :
5483  function( message ) {
5484    console.error( message );
5485  };
5486
5487// -------------------------- measurements -------------------------- //
5488
5489var measurements = [
5490  'paddingLeft',
5491  'paddingRight',
5492  'paddingTop',
5493  'paddingBottom',
5494  'marginLeft',
5495  'marginRight',
5496  'marginTop',
5497  'marginBottom',
5498  'borderLeftWidth',
5499  'borderRightWidth',
5500  'borderTopWidth',
5501  'borderBottomWidth'
5502];
5503
5504var measurementsLength = measurements.length;
5505
5506function getZeroSize() {
5507  var size = {
5508    width: 0,
5509    height: 0,
5510    innerWidth: 0,
5511    innerHeight: 0,
5512    outerWidth: 0,
5513    outerHeight: 0
5514  };
5515  for ( var i=0; i < measurementsLength; i++ ) {
5516    var measurement = measurements[i];
5517    size[ measurement ] = 0;
5518  }
5519  return size;
5520}
5521
5522// -------------------------- getStyle -------------------------- //
5523
5524/**
5525 * getStyle, get style of element, check for Firefox bug
5526 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
5527 */
5528function getStyle( elem ) {
5529  var style = getComputedStyle( elem );
5530  if ( !style ) {
5531    logError( 'Style returned ' + style +
5532      '. Are you running this code in a hidden iframe on Firefox? ' +
5533      'See https://bit.ly/getsizebug1' );
5534  }
5535  return style;
5536}
5537
5538// -------------------------- setup -------------------------- //
5539
5540var isSetup = false;
5541
5542var isBoxSizeOuter;
5543
5544/**
5545 * setup
5546 * check isBoxSizerOuter
5547 * do on first getSize() rather than on page load for Firefox bug
5548 */
5549function setup() {
5550  // setup once
5551  if ( isSetup ) {
5552    return;
5553  }
5554  isSetup = true;
5555
5556  // -------------------------- box sizing -------------------------- //
5557
5558  /**
5559   * Chrome & Safari measure the outer-width on style.width on border-box elems
5560   * IE11 & Firefox<29 measures the inner-width
5561   */
5562  var div = document.createElement('div');
5563  div.style.width = '200px';
5564  div.style.padding = '1px 2px 3px 4px';
5565  div.style.borderStyle = 'solid';
5566  div.style.borderWidth = '1px 2px 3px 4px';
5567  div.style.boxSizing = 'border-box';
5568
5569  var body = document.body || document.documentElement;
5570  body.appendChild( div );
5571  var style = getStyle( div );
5572  // round value for browser zoom. desandro/masonry#928
5573  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
5574  getSize.isBoxSizeOuter = isBoxSizeOuter;
5575
5576  body.removeChild( div );
5577}
5578
5579// -------------------------- getSize -------------------------- //
5580
5581function getSize( elem ) {
5582  setup();
5583
5584  // use querySeletor if elem is string
5585  if ( typeof elem == 'string' ) {
5586    elem = document.querySelector( elem );
5587  }
5588
5589  // do not proceed on non-objects
5590  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
5591    return;
5592  }
5593
5594  var style = getStyle( elem );
5595
5596  // if hidden, everything is 0
5597  if ( style.display == 'none' ) {
5598    return getZeroSize();
5599  }
5600
5601  var size = {};
5602  size.width = elem.offsetWidth;
5603  size.height = elem.offsetHeight;
5604
5605  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
5606
5607  // get all measurements
5608  for ( var i=0; i < measurementsLength; i++ ) {
5609    var measurement = measurements[i];
5610    var value = style[ measurement ];
5611    var num = parseFloat( value );
5612    // any 'auto', 'medium' value will be 0
5613    size[ measurement ] = !isNaN( num ) ? num : 0;
5614  }
5615
5616  var paddingWidth = size.paddingLeft + size.paddingRight;
5617  var paddingHeight = size.paddingTop + size.paddingBottom;
5618  var marginWidth = size.marginLeft + size.marginRight;
5619  var marginHeight = size.marginTop + size.marginBottom;
5620  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
5621  var borderHeight = size.borderTopWidth + size.borderBottomWidth;
5622
5623  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
5624
5625  // overwrite width and height if we can get it from style
5626  var styleWidth = getStyleSize( style.width );
5627  if ( styleWidth !== false ) {
5628    size.width = styleWidth +
5629      // add padding and border unless it's already including it
5630      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
5631  }
5632
5633  var styleHeight = getStyleSize( style.height );
5634  if ( styleHeight !== false ) {
5635    size.height = styleHeight +
5636      // add padding and border unless it's already including it
5637      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
5638  }
5639
5640  size.innerWidth = size.width - ( paddingWidth + borderWidth );
5641  size.innerHeight = size.height - ( paddingHeight + borderHeight );
5642
5643  size.outerWidth = size.width + marginWidth;
5644  size.outerHeight = size.height + marginHeight;
5645
5646  return size;
5647}
5648
5649return getSize;
5650
5651});
5652
5653/**
5654 * matchesSelector v2.0.2
5655 * matchesSelector( element, '.selector' )
5656 * MIT license
5657 */
5658
5659/*jshint browser: true, strict: true, undef: true, unused: true */
5660
5661( function( window, factory ) {
5662  /*global define: false, module: false */
5663  'use strict';
5664  // universal module definition
5665  if ( typeof define == 'function' && define.amd ) {
5666    // AMD
5667    define( 'desandro-matches-selector/matches-selector',factory );
5668  } else if ( typeof module == 'object' && module.exports ) {
5669    // CommonJS
5670    module.exports = factory();
5671  } else {
5672    // browser global
5673    window.matchesSelector = factory();
5674  }
5675
5676}( window, function factory() {
5677  'use strict';
5678
5679  var matchesMethod = ( function() {
5680    var ElemProto = window.Element.prototype;
5681    // check for the standard method name first
5682    if ( ElemProto.matches ) {
5683      return 'matches';
5684    }
5685    // check un-prefixed
5686    if ( ElemProto.matchesSelector ) {
5687      return 'matchesSelector';
5688    }
5689    // check vendor prefixes
5690    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
5691
5692    for ( var i=0; i < prefixes.length; i++ ) {
5693      var prefix = prefixes[i];
5694      var method = prefix + 'MatchesSelector';
5695      if ( ElemProto[ method ] ) {
5696        return method;
5697      }
5698    }
5699  })();
5700
5701  return function matchesSelector( elem, selector ) {
5702    return elem[ matchesMethod ]( selector );
5703  };
5704
5705}));
5706
5707/**
5708 * Fizzy UI utils v2.0.7
5709 * MIT license
5710 */
5711
5712/*jshint browser: true, undef: true, unused: true, strict: true */
5713
5714( function( window, factory ) {
5715  // universal module definition
5716  /*jshint strict: false */ /*globals define, module, require */
5717
5718  if ( typeof define == 'function' && define.amd ) {
5719    // AMD
5720    define( 'fizzy-ui-utils/utils',[
5721      'desandro-matches-selector/matches-selector'
5722    ], function( matchesSelector ) {
5723      return factory( window, matchesSelector );
5724    });
5725  } else if ( typeof module == 'object' && module.exports ) {
5726    // CommonJS
5727    module.exports = factory(
5728      window,
5729      require('desandro-matches-selector')
5730    );
5731  } else {
5732    // browser global
5733    window.fizzyUIUtils = factory(
5734      window,
5735      window.matchesSelector
5736    );
5737  }
5738
5739}( window, function factory( window, matchesSelector ) {
5740
5741
5742
5743var utils = {};
5744
5745// ----- extend ----- //
5746
5747// extends objects
5748utils.extend = function( a, b ) {
5749  for ( var prop in b ) {
5750    a[ prop ] = b[ prop ];
5751  }
5752  return a;
5753};
5754
5755// ----- modulo ----- //
5756
5757utils.modulo = function( num, div ) {
5758  return ( ( num % div ) + div ) % div;
5759};
5760
5761// ----- makeArray ----- //
5762
5763var arraySlice = Array.prototype.slice;
5764
5765// turn element or nodeList into an array
5766utils.makeArray = function( obj ) {
5767  if ( Array.isArray( obj ) ) {
5768    // use object if already an array
5769    return obj;
5770  }
5771  // return empty array if undefined or null. #6
5772  if ( obj === null || obj === undefined ) {
5773    return [];
5774  }
5775
5776  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
5777  if ( isArrayLike ) {
5778    // convert nodeList to array
5779    return arraySlice.call( obj );
5780  }
5781
5782  // array of single index
5783  return [ obj ];
5784};
5785
5786// ----- removeFrom ----- //
5787
5788utils.removeFrom = function( ary, obj ) {
5789  var index = ary.indexOf( obj );
5790  if ( index != -1 ) {
5791    ary.splice( index, 1 );
5792  }
5793};
5794
5795// ----- getParent ----- //
5796
5797utils.getParent = function( elem, selector ) {
5798  while ( elem.parentNode && elem != document.body ) {
5799    elem = elem.parentNode;
5800    if ( matchesSelector( elem, selector ) ) {
5801      return elem;
5802    }
5803  }
5804};
5805
5806// ----- getQueryElement ----- //
5807
5808// use element as selector string
5809utils.getQueryElement = function( elem ) {
5810  if ( typeof elem == 'string' ) {
5811    return document.querySelector( elem );
5812  }
5813  return elem;
5814};
5815
5816// ----- handleEvent ----- //
5817
5818// enable .ontype to trigger from .addEventListener( elem, 'type' )
5819utils.handleEvent = function( event ) {
5820  var method = 'on' + event.type;
5821  if ( this[ method ] ) {
5822    this[ method ]( event );
5823  }
5824};
5825
5826// ----- filterFindElements ----- //
5827
5828utils.filterFindElements = function( elems, selector ) {
5829  // make array of elems
5830  elems = utils.makeArray( elems );
5831  var ffElems = [];
5832
5833  elems.forEach( function( elem ) {
5834    // check that elem is an actual element
5835    
5835// START UNCODE EDIT
5836    // if ( !( elem instanceof HTMLElement ) ) {
5837    if ( !( elem instanceof HTMLElement ) && !SiteParameters.is_frontend_editor ) {
5838    // END UNCODE EDIT
vendor: 23,480 bytes, lines 5838-6750
5838
5839      return;
5840    }
5841    // add elem if no selector
5842    if ( !selector ) {
5843      ffElems.push( elem );
5844      return;
5845    }
5846    // filter & find items if we have a selector
5847    // filter
5848    if ( matchesSelector( elem, selector ) ) {
5849      ffElems.push( elem );
5850    }
5851    // find children
5852    var childElems = elem.querySelectorAll( selector );
5853    // concat childElems to filterFound array
5854    for ( var i=0; i < childElems.length; i++ ) {
5855      ffElems.push( childElems[i] );
5856    }
5857  });
5858
5859  return ffElems;
5860};
5861
5862// ----- debounceMethod ----- //
5863
5864utils.debounceMethod = function( _class, methodName, threshold ) {
5865  threshold = threshold || 100;
5866  // original method
5867  var method = _class.prototype[ methodName ];
5868  var timeoutName = methodName + 'Timeout';
5869
5870  _class.prototype[ methodName ] = function() {
5871    var timeout = this[ timeoutName ];
5872    clearTimeout( timeout );
5873
5874    var args = arguments;
5875    var _this = this;
5876    this[ timeoutName ] = setTimeout( function() {
5877      method.apply( _this, args );
5878      delete _this[ timeoutName ];
5879    }, threshold );
5880  };
5881};
5882
5883// ----- docReady ----- //
5884
5885utils.docReady = function( callback ) {
5886  var readyState = document.readyState;
5887  if ( readyState == 'complete' || readyState == 'interactive' ) {
5888    // do async to allow for other scripts to run. metafizzy/flickity#441
5889    setTimeout( callback );
5890  } else {
5891    document.addEventListener( 'DOMContentLoaded', callback );
5892  }
5893};
5894
5895// ----- htmlInit ----- //
5896
5897// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
5898utils.toDashed = function( str ) {
5899  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
5900    return $1 + '-' + $2;
5901  }).toLowerCase();
5902};
5903
5904var console = window.console;
5905/**
5906 * allow user to initialize classes via [data-namespace] or .js-namespace class
5907 * htmlInit( Widget, 'widgetName' )
5908 * options are parsed from data-namespace-options
5909 */
5910utils.htmlInit = function( WidgetClass, namespace ) {
5911  utils.docReady( function() {
5912    var dashedNamespace = utils.toDashed( namespace );
5913    var dataAttr = 'data-' + dashedNamespace;
5914    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
5915    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
5916    var elems = utils.makeArray( dataAttrElems )
5917      .concat( utils.makeArray( jsDashElems ) );
5918    var dataOptionsAttr = dataAttr + '-options';
5919    var jQuery = window.jQuery;
5920
5921    elems.forEach( function( elem ) {
5922      var attr = elem.getAttribute( dataAttr ) ||
5923        elem.getAttribute( dataOptionsAttr );
5924      var options;
5925      try {
5926        options = attr && JSON.parse( attr );
5927      } catch ( error ) {
5928        // log error, do not initialize
5929        if ( console ) {
5930          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
5931          ': ' + error );
5932        }
5933        return;
5934      }
5935      // initialize
5936      var instance = new WidgetClass( elem, options );
5937      // make available via $().data('namespace')
5938      if ( jQuery ) {
5939        jQuery.data( elem, namespace, instance );
5940      }
5941    });
5942
5943  });
5944};
5945
5946// -----  ----- //
5947
5948return utils;
5949
5950}));
5951
5952/**
5953 * Outlayer Item
5954 */
5955
5956( function( window, factory ) {
5957  // universal module definition
5958  /* jshint strict: false */ /* globals define, module, require */
5959  if ( typeof define == 'function' && define.amd ) {
5960    // AMD - RequireJS
5961    define( 'outlayer/item',[
5962        'ev-emitter/ev-emitter',
5963        'get-size/get-size'
5964      ],
5965      factory
5966    );
5967  } else if ( typeof module == 'object' && module.exports ) {
5968    // CommonJS - Browserify, Webpack
5969    module.exports = factory(
5970      require('ev-emitter'),
5971      require('get-size')
5972    );
5973  } else {
5974    // browser global
5975    window.Outlayer = {};
5976    window.Outlayer.Item = factory(
5977      window.EvEmitter,
5978      window.getSize
5979    );
5980  }
5981
5982}( window, function factory( EvEmitter, getSize ) {
5983'use strict';
5984
5985// ----- helpers ----- //
5986
5987function isEmptyObj( obj ) {
5988  for ( var prop in obj ) {
5989    return false;
5990  }
5991  prop = null;
5992  return true;
5993}
5994
5995// -------------------------- CSS3 support -------------------------- //
5996
5997
5998var docElemStyle = document.documentElement.style;
5999
6000var transitionProperty = typeof docElemStyle.transition == 'string' ?
6001  'transition' : 'WebkitTransition';
6002var transformProperty = typeof docElemStyle.transform == 'string' ?
6003  'transform' : 'WebkitTransform';
6004
6005var transitionEndEvent = {
6006  WebkitTransition: 'webkitTransitionEnd',
6007  transition: 'transitionend'
6008}[ transitionProperty ];
6009
6010// cache all vendor properties that could have vendor prefix
6011var vendorProperties = {
6012  transform: transformProperty,
6013  transition: transitionProperty,
6014  transitionDuration: transitionProperty + 'Duration',
6015  transitionProperty: transitionProperty + 'Property',
6016  transitionDelay: transitionProperty + 'Delay'
6017};
6018
6019// -------------------------- Item -------------------------- //
6020
6021function Item( element, layout ) {
6022  if ( !element ) {
6023    return;
6024  }
6025
6026  this.element = element;
6027  // parent layout class, i.e. Masonry, Isotope, or Packery
6028  this.layout = layout;
6029  this.position = {
6030    x: 0,
6031    y: 0
6032  };
6033
6034  this._create();
6035}
6036
6037// inherit EvEmitter
6038var proto = Item.prototype = Object.create( EvEmitter.prototype );
6039proto.constructor = Item;
6040
6041proto._create = function() {
6042  // transition objects
6043  this._transn = {
6044    ingProperties: {},
6045    clean: {},
6046    onEnd: {}
6047  };
6048
6049  this.css({
6050    position: 'absolute'
6051  });
6052};
6053
6054// trigger specified handler for event type
6055proto.handleEvent = function( event ) {
6056  var method = 'on' + event.type;
6057  if ( this[ method ] ) {
6058    this[ method ]( event );
6059  }
6060};
6061
6062proto.getSize = function() {
6063  this.size = getSize( this.element );
6064};
6065
6066/**
6067 * apply CSS styles to element
6068 * @param {Object} style
6069 */
6070proto.css = function( style ) {
6071  var elemStyle = this.element.style;
6072
6073  for ( var prop in style ) {
6074    // use vendor property if available
6075    var supportedProp = vendorProperties[ prop ] || prop;
6076    elemStyle[ supportedProp ] = style[ prop ];
6077  }
6078};
6079
6080 // measure position, and sets it
6081proto.getPosition = function() {
6082  var style = getComputedStyle( this.element );
6083  var isOriginLeft = this.layout._getOption('originLeft');
6084  var isOriginTop = this.layout._getOption('originTop');
6085  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
6086  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
6087  var x = parseFloat( xValue );
6088  var y = parseFloat( yValue );
6089  // convert percent to pixels
6090  var layoutSize = this.layout.size;
6091  if ( xValue.indexOf('%') != -1 ) {
6092    x = ( x / 100 ) * layoutSize.width;
6093  }
6094  if ( yValue.indexOf('%') != -1 ) {
6095    y = ( y / 100 ) * layoutSize.height;
6096  }
6097  // clean up 'auto' or other non-integer values
6098  x = isNaN( x ) ? 0 : x;
6099  y = isNaN( y ) ? 0 : y;
6100  // remove padding from measurement
6101  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
6102  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
6103
6104  this.position.x = x;
6105  this.position.y = y;
6106};
6107
6108// set settled position, apply padding
6109proto.layoutPosition = function() {
6110  var layoutSize = this.layout.size;
6111  var style = {};
6112  var isOriginLeft = this.layout._getOption('originLeft');
6113  var isOriginTop = this.layout._getOption('originTop');
6114
6115  // x
6116  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
6117  var xProperty = isOriginLeft ? 'left' : 'right';
6118  var xResetProperty = isOriginLeft ? 'right' : 'left';
6119
6120  var x = this.position.x + layoutSize[ xPadding ];
6121  // set in percentage or pixels
6122  style[ xProperty ] = this.getXValue( x );
6123  // reset other property
6124  style[ xResetProperty ] = '';
6125
6126  // y
6127  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
6128  var yProperty = isOriginTop ? 'top' : 'bottom';
6129  var yResetProperty = isOriginTop ? 'bottom' : 'top';
6130
6131  var y = this.position.y + layoutSize[ yPadding ];
6132  // set in percentage or pixels
6133  style[ yProperty ] = this.getYValue( y );
6134  // reset other property
6135  style[ yResetProperty ] = '';
6136
6137  this.css( style );
6138  this.emitEvent( 'layout', [ this ] );
6139};
6140
6141proto.getXValue = function( x ) {
6142  var isHorizontal = this.layout._getOption('horizontal');
6143  return this.layout.options.percentPosition && !isHorizontal ?
6144    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
6145};
6146
6147proto.getYValue = function( y ) {
6148  var isHorizontal = this.layout._getOption('horizontal');
6149  return this.layout.options.percentPosition && isHorizontal ?
6150    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
6151};
6152
6153proto._transitionTo = function( x, y ) {
6154  this.getPosition();
6155  // get current x & y from top/left
6156  var curX = this.position.x;
6157  var curY = this.position.y;
6158
6159  var didNotMove = x == this.position.x && y == this.position.y;
6160
6161  // save end position
6162  this.setPosition( x, y );
6163
6164  // if did not move and not transitioning, just go to layout
6165  if ( didNotMove && !this.isTransitioning ) {
6166    this.layoutPosition();
6167    return;
6168  }
6169
6170  var transX = x - curX;
6171  var transY = y - curY;
6172  var transitionStyle = {};
6173  transitionStyle.transform = this.getTranslate( transX, transY );
6174
6175  this.transition({
6176    to: transitionStyle,
6177    onTransitionEnd: {
6178      transform: this.layoutPosition
6179    },
6180    isCleaning: true
6181  });
6182};
6183
6184proto.getTranslate = function( x, y ) {
6185  // flip cooridinates if origin on right or bottom
6186  var isOriginLeft = this.layout._getOption('originLeft');
6187  var isOriginTop = this.layout._getOption('originTop');
6188  x = isOriginLeft ? x : -x;
6189  y = isOriginTop ? y : -y;
6190  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
6191};
6192
6193// non transition + transform support
6194proto.goTo = function( x, y ) {
6195  this.setPosition( x, y );
6196  this.layoutPosition();
6197};
6198
6199proto.moveTo = proto._transitionTo;
6200
6201proto.setPosition = function( x, y ) {
6202  this.position.x = parseFloat( x );
6203  this.position.y = parseFloat( y );
6204};
6205
6206// ----- transition ----- //
6207
6208/**
6209 * @param {Object} style - CSS
6210 * @param {Function} onTransitionEnd
6211 */
6212
6213// non transition, just trigger callback
6214proto._nonTransition = function( args ) {
6215  this.css( args.to );
6216  if ( args.isCleaning ) {
6217    this._removeStyles( args.to );
6218  }
6219  for ( var prop in args.onTransitionEnd ) {
6220    args.onTransitionEnd[ prop ].call( this );
6221  }
6222};
6223
6224/**
6225 * proper transition
6226 * @param {Object} args - arguments
6227 *   @param {Object} to - style to transition to
6228 *   @param {Object} from - style to start transition from
6229 *   @param {Boolean} isCleaning - removes transition styles after transition
6230 *   @param {Function} onTransitionEnd - callback
6231 */
6232proto.transition = function( args ) {
6233  // redirect to nonTransition if no transition duration
6234  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
6235    this._nonTransition( args );
6236    return;
6237  }
6238
6239  var _transition = this._transn;
6240  // keep track of onTransitionEnd callback by css property
6241  for ( var prop in args.onTransitionEnd ) {
6242    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
6243  }
6244  // keep track of properties that are transitioning
6245  for ( prop in args.to ) {
6246    _transition.ingProperties[ prop ] = true;
6247    // keep track of properties to clean up when transition is done
6248    if ( args.isCleaning ) {
6249      _transition.clean[ prop ] = true;
6250    }
6251  }
6252
6253  // set from styles
6254  if ( args.from ) {
6255    this.css( args.from );
6256    // force redraw. http://blog.alexmaccaw.com/css-transitions
6257    var h = this.element.offsetHeight;
6258    // hack for JSHint to hush about unused var
6259    h = null;
6260  }
6261  // enable transition
6262  this.enableTransition( args.to );
6263  // set styles that are transitioning
6264  this.css( args.to );
6265
6266  this.isTransitioning = true;
6267
6268};
6269
6270// dash before all cap letters, including first for
6271// WebkitTransform => -webkit-transform
6272function toDashedAll( str ) {
6273  return str.replace( /([A-Z])/g, function( $1 ) {
6274    return '-' + $1.toLowerCase();
6275  });
6276}
6277
6278var transitionProps = 'opacity,' + toDashedAll( transformProperty );
6279
6280proto.enableTransition = function(/* style */) {
6281  // HACK changing transitionProperty during a transition
6282  // will cause transition to jump
6283  if ( this.isTransitioning ) {
6284    return;
6285  }
6286
6287  // make `transition: foo, bar, baz` from style object
6288  // HACK un-comment this when enableTransition can work
6289  // while a transition is happening
6290  // var transitionValues = [];
6291  // for ( var prop in style ) {
6292  //   // dash-ify camelCased properties like WebkitTransition
6293  //   prop = vendorProperties[ prop ] || prop;
6294  //   transitionValues.push( toDashedAll( prop ) );
6295  // }
6296  // munge number to millisecond, to match stagger
6297  var duration = this.layout.options.transitionDuration;
6298  duration = typeof duration == 'number' ? duration + 'ms' : duration;
6299  // enable transition styles
6300  this.css({
6301    transitionProperty: transitionProps,
6302    transitionDuration: duration,
6303    transitionDelay: this.staggerDelay || 0
6304  });
6305  // listen for transition end event
6306  this.element.addEventListener( transitionEndEvent, this, false );
6307};
6308
6309// ----- events ----- //
6310
6311proto.onwebkitTransitionEnd = function( event ) {
6312  this.ontransitionend( event );
6313};
6314
6315proto.onotransitionend = function( event ) {
6316  this.ontransitionend( event );
6317};
6318
6319// properties that I munge to make my life easier
6320var dashedVendorProperties = {
6321  '-webkit-transform': 'transform'
6322};
6323
6324proto.ontransitionend = function( event ) {
6325  // disregard bubbled events from children
6326  if ( event.target !== this.element ) {
6327    return;
6328  }
6329  var _transition = this._transn;
6330  // get property name of transitioned property, convert to prefix-free
6331  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
6332
6333  // remove property that has completed transitioning
6334  delete _transition.ingProperties[ propertyName ];
6335  // check if any properties are still transitioning
6336  if ( isEmptyObj( _transition.ingProperties ) ) {
6337    // all properties have completed transitioning
6338    this.disableTransition();
6339  }
6340  // clean style
6341  if ( propertyName in _transition.clean ) {
6342    // clean up style
6343    this.element.style[ event.propertyName ] = '';
6344    delete _transition.clean[ propertyName ];
6345  }
6346  // trigger onTransitionEnd callback
6347  if ( propertyName in _transition.onEnd ) {
6348    var onTransitionEnd = _transition.onEnd[ propertyName ];
6349    onTransitionEnd.call( this );
6350    delete _transition.onEnd[ propertyName ];
6351  }
6352
6353  this.emitEvent( 'transitionEnd', [ this ] );
6354};
6355
6356proto.disableTransition = function() {
6357  this.removeTransitionStyles();
6358  this.element.removeEventListener( transitionEndEvent, this, false );
6359  this.isTransitioning = false;
6360};
6361
6362/**
6363 * removes style property from element
6364 * @param {Object} style
6365**/
6366proto._removeStyles = function( style ) {
6367  // clean up transition styles
6368  var cleanStyle = {};
6369  for ( var prop in style ) {
6370    cleanStyle[ prop ] = '';
6371  }
6372  this.css( cleanStyle );
6373};
6374
6375var cleanTransitionStyle = {
6376  transitionProperty: '',
6377  transitionDuration: '',
6378  transitionDelay: ''
6379};
6380
6381proto.removeTransitionStyles = function() {
6382  // remove transition
6383  this.css( cleanTransitionStyle );
6384};
6385
6386// ----- stagger ----- //
6387
6388proto.stagger = function( delay ) {
6389  delay = isNaN( delay ) ? 0 : delay;
6390  this.staggerDelay = delay + 'ms';
6391};
6392
6393// ----- show/hide/remove ----- //
6394
6395// remove element from DOM
6396proto.removeElem = function() {
6397  this.element.parentNode.removeChild( this.element );
6398  // remove display: none
6399  this.css({ display: '' });
6400  this.emitEvent( 'remove', [ this ] );
6401};
6402
6403proto.remove = function() {
6404  // just remove element if no transition support or no transition
6405  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
6406    this.removeElem();
6407    return;
6408  }
6409
6410  // start transition
6411  this.once( 'transitionEnd', function() {
6412    this.removeElem();
6413  });
6414  this.hide();
6415};
6416
6417proto.reveal = function() {
6418  delete this.isHidden;
6419  // remove display: none
6420  this.css({ display: '' });
6421
6422  var options = this.layout.options;
6423
6424  var onTransitionEnd = {};
6425  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
6426  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
6427
6428  this.transition({
6429    from: options.hiddenStyle,
6430    to: options.visibleStyle,
6431    isCleaning: true,
6432    onTransitionEnd: onTransitionEnd
6433  });
6434};
6435
6436proto.onRevealTransitionEnd = function() {
6437  // check if still visible
6438  // during transition, item may have been hidden
6439  if ( !this.isHidden ) {
6440    this.emitEvent('reveal');
6441  }
6442};
6443
6444/**
6445 * get style property use for hide/reveal transition end
6446 * @param {String} styleProperty - hiddenStyle/visibleStyle
6447 * @returns {String}
6448 */
6449proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
6450  var optionStyle = this.layout.options[ styleProperty ];
6451  // use opacity
6452  if ( optionStyle.opacity ) {
6453    return 'opacity';
6454  }
6455  // get first property
6456  for ( var prop in optionStyle ) {
6457    return prop;
6458  }
6459};
6460
6461proto.hide = function() {
6462  // set flag
6463  this.isHidden = true;
6464  // remove display: none
6465  this.css({ display: '' });
6466
6467  var options = this.layout.options;
6468
6469  var onTransitionEnd = {};
6470  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
6471  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
6472
6473  this.transition({
6474    from: options.visibleStyle,
6475    to: options.hiddenStyle,
6476    // keep hidden stuff hidden
6477    isCleaning: true,
6478    onTransitionEnd: onTransitionEnd
6479  });
6480};
6481
6482proto.onHideTransitionEnd = function() {
6483  // check if still hidden
6484  // during transition, item may have been un-hidden
6485  if ( this.isHidden ) {
6486    this.css({ display: 'none' });
6487    this.emitEvent('hide');
6488  }
6489};
6490
6491proto.destroy = function() {
6492  this.css({
6493    position: '',
6494    left: '',
6495    right: '',
6496    top: '',
6497    bottom: '',
6498    transition: '',
6499    transform: ''
6500  });
6501};
6502
6503return Item;
6504
6505}));
6506
6507/*!
6508 * Outlayer v2.1.1
6509 * the brains and guts of a layout library
6510 * MIT license
6511 */
6512
6513( function( window, factory ) {
6514  'use strict';
6515  // universal module definition
6516  /* jshint strict: false */ /* globals define, module, require */
6517  if ( typeof define == 'function' && define.amd ) {
6518    // AMD - RequireJS
6519    define( 'outlayer/outlayer',[
6520        'ev-emitter/ev-emitter',
6521        'get-size/get-size',
6522        'fizzy-ui-utils/utils',
6523        './item'
6524      ],
6525      function( EvEmitter, getSize, utils, Item ) {
6526        return factory( window, EvEmitter, getSize, utils, Item);
6527      }
6528    );
6529  } else if ( typeof module == 'object' && module.exports ) {
6530    // CommonJS - Browserify, Webpack
6531    module.exports = factory(
6532      window,
6533      require('ev-emitter'),
6534      require('get-size'),
6535      require('fizzy-ui-utils'),
6536      require('./item')
6537    );
6538  } else {
6539    // browser global
6540    window.Outlayer = factory(
6541      window,
6542      window.EvEmitter,
6543      window.getSize,
6544      window.fizzyUIUtils,
6545      window.Outlayer.Item
6546    );
6547  }
6548
6549}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
6550'use strict';
6551
6552// ----- vars ----- //
6553
6554var console = window.console;
6555var jQuery = window.jQuery;
6556var noop = function() {};
6557
6558// -------------------------- Outlayer -------------------------- //
6559
6560// globally unique identifiers
6561var GUID = 0;
6562// internal store of all Outlayer intances
6563var instances = {};
6564
6565
6566/**
6567 * @param {Element, String} element
6568 * @param {Object} options
6569 * @constructor
6570 */
6571function Outlayer( element, options ) {
6572  var queryElement = utils.getQueryElement( element );
6573  if ( !queryElement ) {
6574    if ( console ) {
6575      console.error( 'Bad element for ' + this.constructor.namespace +
6576        ': ' + ( queryElement || element ) );
6577    }
6578    return;
6579  }
6580  this.element = queryElement;
6581  // add jQuery
6582  if ( jQuery ) {
6583    this.$element = jQuery( this.element );
6584  }
6585
6586  // options
6587  this.options = utils.extend( {}, this.constructor.defaults );
6588  this.option( options );
6589
6590  // add id for Outlayer.getFromElement
6591  var id = ++GUID;
6592  this.element.outlayerGUID = id; // expando
6593  instances[ id ] = this; // associate via id
6594
6595  // kick it off
6596  this._create();
6597
6598  var isInitLayout = this._getOption('initLayout');
6599  if ( isInitLayout ) {
6600    this.layout();
6601  }
6602}
6603
6604// settings are for internal use only
6605Outlayer.namespace = 'outlayer';
6606Outlayer.Item = Item;
6607
6608// default options
6609Outlayer.defaults = {
6610  containerStyle: {
6611    position: 'relative'
6612  },
6613  initLayout: true,
6614  originLeft: true,
6615  originTop: true,
6616  resize: true,
6617  resizeContainer: true,
6618  // item options
6619  transitionDuration: '0.4s',
6620  hiddenStyle: {
6621    opacity: 0,
6622    transform: 'scale(0.001)'
6623  },
6624  visibleStyle: {
6625    opacity: 1,
6626    transform: 'scale(1)'
6627  }
6628};
6629
6630var proto = Outlayer.prototype;
6631// inherit EvEmitter
6632utils.extend( proto, EvEmitter.prototype );
6633
6634/**
6635 * set options
6636 * @param {Object} opts
6637 */
6638proto.option = function( opts ) {
6639  utils.extend( this.options, opts );
6640};
6641
6642/**
6643 * get backwards compatible option value, check old name
6644 */
6645proto._getOption = function( option ) {
6646  var oldOption = this.constructor.compatOptions[ option ];
6647  return oldOption && this.options[ oldOption ] !== undefined ?
6648    this.options[ oldOption ] : this.options[ option ];
6649};
6650
6651Outlayer.compatOptions = {
6652  // currentName: oldName
6653  initLayout: 'isInitLayout',
6654  horizontal: 'isHorizontal',
6655  layoutInstant: 'isLayoutInstant',
6656  originLeft: 'isOriginLeft',
6657  originTop: 'isOriginTop',
6658  resize: 'isResizeBound',
6659  resizeContainer: 'isResizingContainer'
6660};
6661
6662proto._create = function() {
6663  // get items from children
6664  this.reloadItems();
6665  // elements that affect layout, but are not laid out
6666  this.stamps = [];
6667  this.stamp( this.options.stamp );
6668  // set container style
6669  utils.extend( this.element.style, this.options.containerStyle );
6670
6671  // bind resize method
6672  var canBindResize = this._getOption('resize');
6673  if ( canBindResize ) {
6674    this.bindResize();
6675  }
6676};
6677
6678// goes through all children again and gets bricks in proper order
6679proto.reloadItems = function() {
6680  // collection of item elements
6681  this.items = this._itemize( this.element.children );
6682};
6683
6684
6685/**
6686 * turn elements into Outlayer.Items to be used in layout
6687 * @param {Array or NodeList or HTMLElement} elems
6688 * @returns {Array} items - collection of new Outlayer Items
6689 */
6690proto._itemize = function( elems ) {
6691
6692  var itemElems = this._filterFindItemElements( elems );
6693  var Item = this.constructor.Item;
6694
6695  // create new Outlayer Items for collection
6696  var items = [];
6697  for ( var i=0; i < itemElems.length; i++ ) {
6698    var elem = itemElems[i];
6699    var item = new Item( elem, this );
6700    items.push( item );
6701  }
6702
6703  return items;
6704};
6705
6706/**
6707 * get item elements to be used in layout
6708 * @param {Array or NodeList or HTMLElement} elems
6709 * @returns {Array} items - item elements
6710 */
6711proto._filterFindItemElements = function( elems ) {
6712  return utils.filterFindElements( elems, this.options.itemSelector );
6713};
6714
6715/**
6716 * getter method for getting item elements
6717 * @returns {Array} elems - collection of item elements
6718 */
6719proto.getItemElements = function() {
6720  return this.items.map( function( item ) {
6721    return item.element;
6722  });
6723};
6724
6725// ----- init & layout ----- //
6726
6727/**
6728 * lays out all items
6729 */
6730proto.layout = function() {
6731  this._resetLayout();
6732  this._manageStamps();
6733
6734  // don't animate first layout
6735  var layoutInstant = this._getOption('layoutInstant');
6736  var isInstant = layoutInstant !== undefined ?
6737    layoutInstant : !this._isLayoutInited;
6738  this.layoutItems( this.items, isInstant );
6739
6740  // flag for initalized
6741  this._isLayoutInited = true;
6742};
6743
6744// _init is alias for layout
6745proto._init = proto.layout;
6746
6747/**
6748 * logic before any new layout
6749 */
6750proto._resetLayout = function() {
vendor: 13,499 bytes, lines 6751-7319
6751  this.getSize();
6752};
6753
6754
6755proto.getSize = function() {
6756  this.size = getSize( this.element );
6757};
6758
6759/**
6760 * get measurement from option, for columnWidth, rowHeight, gutter
6761 * if option is String -> get element from selector string, & get size of element
6762 * if option is Element -> get size of element
6763 * else use option as a number
6764 *
6765 * @param {String} measurement
6766 * @param {String} size - width or height
6767 * @private
6768 */
6769proto._getMeasurement = function( measurement, size ) {
6770  var option = this.options[ measurement ];
6771  var elem;
6772  if ( !option ) {
6773    // default to 0
6774    this[ measurement ] = 0;
6775  } else {
6776    // use option as an element
6777    if ( typeof option == 'string' ) {
6778      elem = this.element.querySelector( option );
6779    } else if ( option instanceof HTMLElement ) {
6780      elem = option;
6781    }
6782    // use size of element, if element
6783    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
6784  }
6785};
6786
6787/**
6788 * layout a collection of item elements
6789 * @api public
6790 */
6791proto.layoutItems = function( items, isInstant ) {
6792  items = this._getItemsForLayout( items );
6793
6794  this._layoutItems( items, isInstant );
6795
6796  this._postLayout();
6797};
6798
6799/**
6800 * get the items to be laid out
6801 * you may want to skip over some items
6802 * @param {Array} items
6803 * @returns {Array} items
6804 */
6805proto._getItemsForLayout = function( items ) {
6806  return items.filter( function( item ) {
6807    return !item.isIgnored;
6808  });
6809};
6810
6811/**
6812 * layout items
6813 * @param {Array} items
6814 * @param {Boolean} isInstant
6815 */
6816proto._layoutItems = function( items, isInstant ) {
6817  this._emitCompleteOnItems( 'layout', items );
6818
6819  if ( !items || !items.length ) {
6820    // no items, emit event with empty array
6821    return;
6822  }
6823
6824  var queue = [];
6825
6826  items.forEach( function( item ) {
6827    // get x/y object from method
6828    var position = this._getItemLayoutPosition( item );
6829    // enqueue
6830    position.item = item;
6831    position.isInstant = isInstant || item.isLayoutInstant;
6832    queue.push( position );
6833  }, this );
6834
6835  this._processLayoutQueue( queue );
6836};
6837
6838/**
6839 * get item layout position
6840 * @param {Outlayer.Item} item
6841 * @returns {Object} x and y position
6842 */
6843proto._getItemLayoutPosition = function( /* item */ ) {
6844  return {
6845    x: 0,
6846    y: 0
6847  };
6848};
6849
6850/**
6851 * iterate over array and position each item
6852 * Reason being - separating this logic prevents 'layout invalidation'
6853 * thx @paul_irish
6854 * @param {Array} queue
6855 */
6856proto._processLayoutQueue = function( queue ) {
6857  this.updateStagger();
6858  queue.forEach( function( obj, i ) {
6859    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
6860  }, this );
6861};
6862
6863// set stagger from option in milliseconds number
6864proto.updateStagger = function() {
6865  var stagger = this.options.stagger;
6866  if ( stagger === null || stagger === undefined ) {
6867    this.stagger = 0;
6868    return;
6869  }
6870  this.stagger = getMilliseconds( stagger );
6871  return this.stagger;
6872};
6873
6874/**
6875 * Sets position of item in DOM
6876 * @param {Outlayer.Item} item
6877 * @param {Number} x - horizontal position
6878 * @param {Number} y - vertical position
6879 * @param {Boolean} isInstant - disables transitions
6880 */
6881proto._positionItem = function( item, x, y, isInstant, i ) {
6882  if ( isInstant ) {
6883    // if not transition, just set CSS
6884    item.goTo( x, y );
6885  } else {
6886    item.stagger( i * this.stagger );
6887    item.moveTo( x, y );
6888  }
6889};
6890
6891/**
6892 * Any logic you want to do after each layout,
6893 * i.e. size the container
6894 */
6895proto._postLayout = function() {
6896  this.resizeContainer();
6897};
6898
6899proto.resizeContainer = function() {
6900  var isResizingContainer = this._getOption('resizeContainer');
6901  if ( !isResizingContainer ) {
6902    return;
6903  }
6904  var size = this._getContainerSize();
6905  if ( size ) {
6906    this._setContainerMeasure( size.width, true );
6907    this._setContainerMeasure( size.height, false );
6908  }
6909};
6910
6911/**
6912 * Sets width or height of container if returned
6913 * @returns {Object} size
6914 *   @param {Number} width
6915 *   @param {Number} height
6916 */
6917proto._getContainerSize = noop;
6918
6919/**
6920 * @param {Number} measure - size of width or height
6921 * @param {Boolean} isWidth
6922 */
6923proto._setContainerMeasure = function( measure, isWidth ) {
6924  if ( measure === undefined ) {
6925    return;
6926  }
6927
6928  var elemSize = this.size;
6929  // add padding and border width if border box
6930  if ( elemSize.isBorderBox ) {
6931    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
6932      elemSize.borderLeftWidth + elemSize.borderRightWidth :
6933      elemSize.paddingBottom + elemSize.paddingTop +
6934      elemSize.borderTopWidth + elemSize.borderBottomWidth;
6935  }
6936
6937  measure = Math.max( measure, 0 );
6938  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
6939};
6940
6941/**
6942 * emit eventComplete on a collection of items events
6943 * @param {String} eventName
6944 * @param {Array} items - Outlayer.Items
6945 */
6946proto._emitCompleteOnItems = function( eventName, items ) {
6947  var _this = this;
6948  function onComplete() {
6949    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
6950  }
6951
6952  var count = items.length;
6953  if ( !items || !count ) {
6954    onComplete();
6955    return;
6956  }
6957
6958  var doneCount = 0;
6959  function tick() {
6960    doneCount++;
6961    if ( doneCount == count ) {
6962      onComplete();
6963    }
6964  }
6965
6966  // bind callback
6967  items.forEach( function( item ) {
6968    item.once( eventName, tick );
6969  });
6970};
6971
6972/**
6973 * emits events via EvEmitter and jQuery events
6974 * @param {String} type - name of event
6975 * @param {Event} event - original event
6976 * @param {Array} args - extra arguments
6977 */
6978proto.dispatchEvent = function( type, event, args ) {
6979  // add original event to arguments
6980  var emitArgs = event ? [ event ].concat( args ) : args;
6981  this.emitEvent( type, emitArgs );
6982
6983  if ( jQuery ) {
6984    // set this.$element
6985    this.$element = this.$element || jQuery( this.element );
6986    if ( event ) {
6987      // create jQuery event
6988      var $event = jQuery.Event( event );
6989      $event.type = type;
6990      this.$element.trigger( $event, args );
6991    } else {
6992      // just trigger with type if no event available
6993      this.$element.trigger( type, args );
6994    }
6995  }
6996};
6997
6998// -------------------------- ignore & stamps -------------------------- //
6999
7000
7001/**
7002 * keep item in collection, but do not lay it out
7003 * ignored items do not get skipped in layout
7004 * @param {Element} elem
7005 */
7006proto.ignore = function( elem ) {
7007  var item = this.getItem( elem );
7008  if ( item ) {
7009    item.isIgnored = true;
7010  }
7011};
7012
7013/**
7014 * return item to layout collection
7015 * @param {Element} elem
7016 */
7017proto.unignore = function( elem ) {
7018  var item = this.getItem( elem );
7019  if ( item ) {
7020    delete item.isIgnored;
7021  }
7022};
7023
7024/**
7025 * adds elements to stamps
7026 * @param {NodeList, Array, Element, or String} elems
7027 */
7028proto.stamp = function( elems ) {
7029  elems = this._find( elems );
7030  if ( !elems ) {
7031    return;
7032  }
7033
7034  this.stamps = this.stamps.concat( elems );
7035  // ignore
7036  elems.forEach( this.ignore, this );
7037};
7038
7039/**
7040 * removes elements to stamps
7041 * @param {NodeList, Array, or Element} elems
7042 */
7043proto.unstamp = function( elems ) {
7044  elems = this._find( elems );
7045  if ( !elems ){
7046    return;
7047  }
7048
7049  elems.forEach( function( elem ) {
7050    // filter out removed stamp elements
7051    utils.removeFrom( this.stamps, elem );
7052    this.unignore( elem );
7053  }, this );
7054};
7055
7056/**
7057 * finds child elements
7058 * @param {NodeList, Array, Element, or String} elems
7059 * @returns {Array} elems
7060 */
7061proto._find = function( elems ) {
7062  if ( !elems ) {
7063    return;
7064  }
7065  // if string, use argument as selector string
7066  if ( typeof elems == 'string' ) {
7067    elems = this.element.querySelectorAll( elems );
7068  }
7069  elems = utils.makeArray( elems );
7070  return elems;
7071};
7072
7073proto._manageStamps = function() {
7074  if ( !this.stamps || !this.stamps.length ) {
7075    return;
7076  }
7077
7078  this._getBoundingRect();
7079
7080  this.stamps.forEach( this._manageStamp, this );
7081};
7082
7083// update boundingLeft / Top
7084proto._getBoundingRect = function() {
7085  // get bounding rect for container element
7086  var boundingRect = this.element.getBoundingClientRect();
7087  var size = this.size;
7088  this._boundingRect = {
7089    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
7090    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
7091    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
7092    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
7093  };
7094};
7095
7096/**
7097 * @param {Element} stamp
7098**/
7099proto._manageStamp = noop;
7100
7101/**
7102 * get x/y position of element relative to container element
7103 * @param {Element} elem
7104 * @returns {Object} offset - has left, top, right, bottom
7105 */
7106proto._getElementOffset = function( elem ) {
7107  var boundingRect = elem.getBoundingClientRect();
7108  var thisRect = this._boundingRect;
7109  var size = getSize( elem );
7110  var offset = {
7111    left: boundingRect.left - thisRect.left - size.marginLeft,
7112    top: boundingRect.top - thisRect.top - size.marginTop,
7113    right: thisRect.right - boundingRect.right - size.marginRight,
7114    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
7115  };
7116  return offset;
7117};
7118
7119// -------------------------- resize -------------------------- //
7120
7121// enable event handlers for listeners
7122// i.e. resize -> onresize
7123proto.handleEvent = utils.handleEvent;
7124
7125/**
7126 * Bind layout to window resizing
7127 */
7128proto.bindResize = function() {
7129  window.addEventListener( 'resize', this );
7130  this.isResizeBound = true;
7131};
7132
7133/**
7134 * Unbind layout to window resizing
7135 */
7136proto.unbindResize = function() {
7137  window.removeEventListener( 'resize', this );
7138  this.isResizeBound = false;
7139};
7140
7141proto.onresize = function() {
7142  this.resize();
7143};
7144
7145utils.debounceMethod( Outlayer, 'onresize', 100 );
7146
7147proto.resize = function() {
7148  // don't trigger if size did not change
7149  // or if resize was unbound. See #9
7150  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
7151    return;
7152  }
7153
7154  this.layout();
7155};
7156
7157/**
7158 * check if layout is needed post layout
7159 * @returns Boolean
7160 */
7161proto.needsResizeLayout = function() {
7162  var size = getSize( this.element );
7163  // check that this.size and size are there
7164  // IE8 triggers resize on body size change, so they might not be
7165  var hasSizes = this.size && size;
7166  return hasSizes && size.innerWidth !== this.size.innerWidth;
7167};
7168
7169// -------------------------- methods -------------------------- //
7170
7171/**
7172 * add items to Outlayer instance
7173 * @param {Array or NodeList or Element} elems
7174 * @returns {Array} items - Outlayer.Items
7175**/
7176proto.addItems = function( elems ) {
7177  var items = this._itemize( elems );
7178  // add items to collection
7179  if ( items.length ) {
7180    this.items = this.items.concat( items );
7181  }
7182  return items;
7183};
7184
7185/**
7186 * Layout newly-appended item elements
7187 * @param {Array or NodeList or Element} elems
7188 */
7189proto.appended = function( elems ) {
7190  var items = this.addItems( elems );
7191  if ( !items.length ) {
7192    return;
7193  }
7194  // layout and reveal just the new items
7195  this.layoutItems( items, true );
7196  this.reveal( items );
7197};
7198
7199/**
7200 * Layout prepended elements
7201 * @param {Array or NodeList or Element} elems
7202 */
7203proto.prepended = function( elems ) {
7204  var items = this._itemize( elems );
7205  if ( !items.length ) {
7206    return;
7207  }
7208  // add items to beginning of collection
7209  var previousItems = this.items.slice(0);
7210  this.items = items.concat( previousItems );
7211  // start new layout
7212  this._resetLayout();
7213  this._manageStamps();
7214  // layout new stuff without transition
7215  this.layoutItems( items, true );
7216  this.reveal( items );
7217  // layout previous items
7218  this.layoutItems( previousItems );
7219};
7220
7221/**
7222 * reveal a collection of items
7223 * @param {Array of Outlayer.Items} items
7224 */
7225proto.reveal = function( items ) {
7226  this._emitCompleteOnItems( 'reveal', items );
7227  if ( !items || !items.length ) {
7228    return;
7229  }
7230  var stagger = this.updateStagger();
7231  items.forEach( function( item, i ) {
7232    item.stagger( i * stagger );
7233    item.reveal();
7234  });
7235};
7236
7237/**
7238 * hide a collection of items
7239 * @param {Array of Outlayer.Items} items
7240 */
7241proto.hide = function( items ) {
7242  this._emitCompleteOnItems( 'hide', items );
7243  if ( !items || !items.length ) {
7244    return;
7245  }
7246  var stagger = this.updateStagger();
7247  items.forEach( function( item, i ) {
7248    item.stagger( i * stagger );
7249    item.hide();
7250  });
7251};
7252
7253/**
7254 * reveal item elements
7255 * @param {Array}, {Element}, {NodeList} items
7256 */
7257proto.revealItemElements = function( elems ) {
7258  var items = this.getItems( elems );
7259  this.reveal( items );
7260};
7261
7262/**
7263 * hide item elements
7264 * @param {Array}, {Element}, {NodeList} items
7265 */
7266proto.hideItemElements = function( elems ) {
7267  var items = this.getItems( elems );
7268  this.hide( items );
7269};
7270
7271/**
7272 * get Outlayer.Item, given an Element
7273 * @param {Element} elem
7274 * @param {Function} callback
7275 * @returns {Outlayer.Item} item
7276 */
7277proto.getItem = function( elem ) {
7278  // loop through items to get the one that matches
7279  for ( var i=0; i < this.items.length; i++ ) {
7280    var item = this.items[i];
7281    if ( item.element == elem ) {
7282      // return item
7283      return item;
7284    }
7285  }
7286};
7287
7288/**
7289 * get collection of Outlayer.Items, given Elements
7290 * @param {Array} elems
7291 * @returns {Array} items - Outlayer.Items
7292 */
7293proto.getItems = function( elems ) {
7294  elems = utils.makeArray( elems );
7295  var items = [];
7296  elems.forEach( function( elem ) {
7297    var item = this.getItem( elem );
7298    if ( item ) {
7299      items.push( item );
7300    }
7301  }, this );
7302
7303  return items;
7304};
7305
7306/**
7307 * remove element(s) from instance and DOM
7308 * @param {Array or NodeList or Element} elems
7309 */
7310proto.remove = function( elems ) {
7311  var removeItems = this.getItems( elems );
7312
7313  this._emitCompleteOnItems( 'remove', removeItems );
7314
7315  // bail if no items to remove
7316  if ( !removeItems || !removeItems.length ) {
7317    return;
7318  }
7319
vendor: 38,285 bytes, lines 7320-8743
7320  removeItems.forEach( function( item ) {
7321    item.remove();
7322    // remove item from collection
7323    utils.removeFrom( this.items, item );
7324  }, this );
7325};
7326
7327// ----- destroy ----- //
7328
7329// remove and disable Outlayer instance
7330proto.destroy = function() {
7331  // clean up dynamic styles
7332  var style = this.element.style;
7333  style.height = '';
7334  style.position = '';
7335  style.width = '';
7336  // destroy items
7337  this.items.forEach( function( item ) {
7338    item.destroy();
7339  });
7340
7341  this.unbindResize();
7342
7343  var id = this.element.outlayerGUID;
7344  delete instances[ id ]; // remove reference to instance by id
7345  delete this.element.outlayerGUID;
7346  // remove data for jQuery
7347  if ( jQuery ) {
7348    jQuery.removeData( this.element, this.constructor.namespace );
7349  }
7350
7351};
7352
7353// -------------------------- data -------------------------- //
7354
7355/**
7356 * get Outlayer instance from element
7357 * @param {Element} elem
7358 * @returns {Outlayer}
7359 */
7360Outlayer.data = function( elem ) {
7361  elem = utils.getQueryElement( elem );
7362  var id = elem && elem.outlayerGUID;
7363  return id && instances[ id ];
7364};
7365
7366
7367// -------------------------- create Outlayer class -------------------------- //
7368
7369/**
7370 * create a layout class
7371 * @param {String} namespace
7372 */
7373Outlayer.create = function( namespace, options ) {
7374  // sub-class Outlayer
7375  var Layout = subclass( Outlayer );
7376  // apply new options and compatOptions
7377  Layout.defaults = utils.extend( {}, Outlayer.defaults );
7378  utils.extend( Layout.defaults, options );
7379  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );
7380
7381  Layout.namespace = namespace;
7382
7383  Layout.data = Outlayer.data;
7384
7385  // sub-class Item
7386  Layout.Item = subclass( Item );
7387
7388  // -------------------------- declarative -------------------------- //
7389
7390  utils.htmlInit( Layout, namespace );
7391
7392  // -------------------------- jQuery bridge -------------------------- //
7393
7394  // make into jQuery plugin
7395  if ( jQuery && jQuery.bridget ) {
7396    jQuery.bridget( namespace, Layout );
7397  }
7398
7399  return Layout;
7400};
7401
7402function subclass( Parent ) {
7403  function SubClass() {
7404    Parent.apply( this, arguments );
7405  }
7406
7407  SubClass.prototype = Object.create( Parent.prototype );
7408  SubClass.prototype.constructor = SubClass;
7409
7410  return SubClass;
7411}
7412
7413// ----- helpers ----- //
7414
7415// how many milliseconds are in each unit
7416var msUnits = {
7417  ms: 1,
7418  s: 1000
7419};
7420
7421// munge time-like parameter into millisecond number
7422// '0.4s' -> 40
7423function getMilliseconds( time ) {
7424  if ( typeof time == 'number' ) {
7425    return time;
7426  }
7427  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
7428  var num = matches && matches[1];
7429  var unit = matches && matches[2];
7430  if ( !num.length ) {
7431    return 0;
7432  }
7433  num = parseFloat( num );
7434  var mult = msUnits[ unit ] || 1;
7435  return num * mult;
7436}
7437
7438// ----- fin ----- //
7439
7440// back in global
7441Outlayer.Item = Item;
7442
7443return Outlayer;
7444
7445}));
7446
7447/**
7448 * Isotope Item
7449**/
7450
7451( function( window, factory ) {
7452  // universal module definition
7453  /* jshint strict: false */ /*globals define, module, require */
7454  if ( typeof define == 'function' && define.amd ) {
7455    // AMD
7456    define( 'isotope-layout/js/item',[
7457        'outlayer/outlayer'
7458      ],
7459      factory );
7460  } else if ( typeof module == 'object' && module.exports ) {
7461    // CommonJS
7462    module.exports = factory(
7463      require('outlayer')
7464    );
7465  } else {
7466    // browser global
7467    window.Isotope = window.Isotope || {};
7468    window.Isotope.Item = factory(
7469      window.Outlayer
7470    );
7471  }
7472
7473}( window, function factory( Outlayer ) {
7474'use strict';
7475
7476// -------------------------- Item -------------------------- //
7477
7478// sub-class Outlayer Item
7479function Item() {
7480  Outlayer.Item.apply( this, arguments );
7481}
7482
7483var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
7484
7485var _create = proto._create;
7486proto._create = function() {
7487  // assign id, used for original-order sorting
7488  this.id = this.layout.itemGUID++;
7489  _create.call( this );
7490  this.sortData = {};
7491};
7492
7493proto.updateSortData = function() {
7494  if ( this.isIgnored ) {
7495    return;
7496  }
7497  // default sorters
7498  this.sortData.id = this.id;
7499  // for backward compatibility
7500  this.sortData['original-order'] = this.id;
7501  this.sortData.random = Math.random();
7502  // go thru getSortData obj and apply the sorters
7503  var getSortData = this.layout.options.getSortData;
7504  var sorters = this.layout._sorters;
7505  for ( var key in getSortData ) {
7506    var sorter = sorters[ key ];
7507    this.sortData[ key ] = sorter( this.element, this );
7508  }
7509};
7510
7511var _destroy = proto.destroy;
7512proto.destroy = function() {
7513  // call super
7514  _destroy.apply( this, arguments );
7515  // reset display, #741
7516  this.css({
7517    display: ''
7518  });
7519};
7520
7521return Item;
7522
7523}));
7524
7525/**
7526 * Isotope LayoutMode
7527 */
7528
7529( function( window, factory ) {
7530  // universal module definition
7531  /* jshint strict: false */ /*globals define, module, require */
7532  if ( typeof define == 'function' && define.amd ) {
7533    // AMD
7534    define( 'isotope-layout/js/layout-mode',[
7535        'get-size/get-size',
7536        'outlayer/outlayer'
7537      ],
7538      factory );
7539  } else if ( typeof module == 'object' && module.exports ) {
7540    // CommonJS
7541    module.exports = factory(
7542      require('get-size'),
7543      require('outlayer')
7544    );
7545  } else {
7546    // browser global
7547    window.Isotope = window.Isotope || {};
7548    window.Isotope.LayoutMode = factory(
7549      window.getSize,
7550      window.Outlayer
7551    );
7552  }
7553
7554}( window, function factory( getSize, Outlayer ) {
7555  'use strict';
7556
7557  // layout mode class
7558  function LayoutMode( isotope ) {
7559    this.isotope = isotope;
7560    // link properties
7561    if ( isotope ) {
7562      this.options = isotope.options[ this.namespace ];
7563      this.element = isotope.element;
7564      this.items = isotope.filteredItems;
7565      this.size = isotope.size;
7566    }
7567  }
7568
7569  var proto = LayoutMode.prototype;
7570
7571  /**
7572   * some methods should just defer to default Outlayer method
7573   * and reference the Isotope instance as `this`
7574  **/
7575  var facadeMethods = [
7576    '_resetLayout',
7577    '_getItemLayoutPosition',
7578    '_manageStamp',
7579    '_getContainerSize',
7580    '_getElementOffset',
7581    'needsResizeLayout',
7582    '_getOption'
7583  ];
7584
7585  facadeMethods.forEach( function( methodName ) {
7586    proto[ methodName ] = function() {
7587      return Outlayer.prototype[ methodName ].apply( this.isotope, arguments );
7588    };
7589  });
7590
7591  // -----  ----- //
7592
7593  // for horizontal layout modes, check vertical size
7594  proto.needsVerticalResizeLayout = function() {
7595    // don't trigger if size did not change
7596    var size = getSize( this.isotope.element );
7597    // check that this.size and size are there
7598    // IE8 triggers resize on body size change, so they might not be
7599    var hasSizes = this.isotope.size && size;
7600    return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
7601  };
7602
7603  // ----- measurements ----- //
7604
7605  proto._getMeasurement = function() {
7606    this.isotope._getMeasurement.apply( this, arguments );
7607  };
7608
7609  proto.getColumnWidth = function() {
7610    this.getSegmentSize( 'column', 'Width' );
7611  };
7612
7613  proto.getRowHeight = function() {
7614    this.getSegmentSize( 'row', 'Height' );
7615  };
7616
7617  /**
7618   * get columnWidth or rowHeight
7619   * segment: 'column' or 'row'
7620   * size 'Width' or 'Height'
7621  **/
7622  proto.getSegmentSize = function( segment, size ) {
7623    var segmentName = segment + size;
7624    var outerSize = 'outer' + size;
7625    // columnWidth / outerWidth // rowHeight / outerHeight
7626    this._getMeasurement( segmentName, outerSize );
7627    // got rowHeight or columnWidth, we can chill
7628    if ( this[ segmentName ] ) {
7629      return;
7630    }
7631    // fall back to item of first element
7632    var firstItemSize = this.getFirstItemSize();
7633    this[ segmentName ] = firstItemSize && firstItemSize[ outerSize ] ||
7634      // or size of container
7635      this.isotope.size[ 'inner' + size ];
7636  };
7637
7638  proto.getFirstItemSize = function() {
7639    var firstItem = this.isotope.filteredItems[0];
7640    return firstItem && firstItem.element && getSize( firstItem.element );
7641  };
7642
7643  // ----- methods that should reference isotope ----- //
7644
7645  proto.layout = function() {
7646    this.isotope.layout.apply( this.isotope, arguments );
7647  };
7648
7649  proto.getSize = function() {
7650    this.isotope.getSize();
7651    this.size = this.isotope.size;
7652  };
7653
7654  // -------------------------- create -------------------------- //
7655
7656  LayoutMode.modes = {};
7657
7658  LayoutMode.create = function( namespace, options ) {
7659
7660    function Mode() {
7661      LayoutMode.apply( this, arguments );
7662    }
7663
7664    Mode.prototype = Object.create( proto );
7665    Mode.prototype.constructor = Mode;
7666
7667    // default options
7668    if ( options ) {
7669      Mode.options = options;
7670    }
7671
7672    Mode.prototype.namespace = namespace;
7673    // register in Isotope
7674    LayoutMode.modes[ namespace ] = Mode;
7675
7676    return Mode;
7677  };
7678
7679  return LayoutMode;
7680
7681}));
7682
7683/*!
7684 * Masonry v4.2.1
7685 * Cascading grid layout library
7686 * https://masonry.desandro.com
7687 * MIT License
7688 * by David DeSandro
7689 */
7690
7691( function( window, factory ) {
7692  // universal module definition
7693  /* jshint strict: false */ /*globals define, module, require */
7694  if ( typeof define == 'function' && define.amd ) {
7695    // AMD
7696    define( 'masonry-layout/masonry',[
7697        'outlayer/outlayer',
7698        'get-size/get-size'
7699      ],
7700      factory );
7701  } else if ( typeof module == 'object' && module.exports ) {
7702    // CommonJS
7703    module.exports = factory(
7704      require('outlayer'),
7705      require('get-size')
7706    );
7707  } else {
7708    // browser global
7709    window.Masonry = factory(
7710      window.Outlayer,
7711      window.getSize
7712    );
7713  }
7714
7715}( window, function factory( Outlayer, getSize ) {
7716
7717
7718
7719// -------------------------- masonryDefinition -------------------------- //
7720
7721  // create an Outlayer layout class
7722  var Masonry = Outlayer.create('masonry');
7723  // isFitWidth -> fitWidth
7724  Masonry.compatOptions.fitWidth = 'isFitWidth';
7725
7726  var proto = Masonry.prototype;
7727
7728  proto._resetLayout = function() {
7729    this.getSize();
7730    this._getMeasurement( 'columnWidth', 'outerWidth' );
7731    this._getMeasurement( 'gutter', 'outerWidth' );
7732    this.measureColumns();
7733
7734    // reset column Y
7735    this.colYs = [];
7736    for ( var i=0; i < this.cols; i++ ) {
7737      this.colYs.push( 0 );
7738    }
7739
7740    this.maxY = 0;
7741    this.horizontalColIndex = 0;
7742  };
7743
7744  proto.measureColumns = function() {
7745    this.getContainerWidth();
7746    // if columnWidth is 0, default to outerWidth of first item
7747    if ( !this.columnWidth ) {
7748      var firstItem = this.items[0];
7749      var firstItemElem = firstItem && firstItem.element;
7750      // columnWidth fall back to item of first element
7751      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
7752        // if first elem has no width, default to size of container
7753        this.containerWidth;
7754    }
7755
7756    var columnWidth = this.columnWidth += this.gutter;
7757
7758    // calculate columns
7759    var containerWidth = this.containerWidth + this.gutter;
7760    var cols = containerWidth / columnWidth;
7761    // fix rounding errors, typically with gutters
7762    var excess = columnWidth - containerWidth % columnWidth;
7763    // if overshoot is less than a pixel, round up, otherwise floor it
7764    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
7765    cols = Math[ mathMethod ]( cols );
7766    this.cols = Math.max( cols, 1 );
7767  };
7768
7769  proto.getContainerWidth = function() {
7770    // container is parent if fit width
7771    var isFitWidth = this._getOption('fitWidth');
7772    var container = isFitWidth ? this.element.parentNode : this.element;
7773    // check that this.size and size are there
7774    // IE8 triggers resize on body size change, so they might not be
7775    var size = getSize( container );
7776    this.containerWidth = size && size.innerWidth;
7777  };
7778
7779  proto._getItemLayoutPosition = function( item ) {
7780    item.getSize();
7781    // how many columns does this brick span
7782    var remainder = item.size.outerWidth % this.columnWidth;
7783    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
7784    // round if off by 1 pixel, otherwise use ceil
7785    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
7786    colSpan = Math.min( colSpan, this.cols );
7787    // use horizontal or top column position
7788    var colPosMethod = this.options.horizontalOrder ?
7789      '_getHorizontalColPosition' : '_getTopColPosition';
7790    var colPosition = this[ colPosMethod ]( colSpan, item );
7791    // position the brick
7792    var position = {
7793      x: this.columnWidth * colPosition.col,
7794      y: colPosition.y
7795    };
7796    // apply setHeight to necessary columns
7797    var setHeight = colPosition.y + item.size.outerHeight;
7798    var setMax = colSpan + colPosition.col;
7799    for ( var i = colPosition.col; i < setMax; i++ ) {
7800      this.colYs[i] = setHeight;
7801    }
7802
7803    return position;
7804  };
7805
7806  proto._getTopColPosition = function( colSpan ) {
7807    var colGroup = this._getTopColGroup( colSpan );
7808    // get the minimum Y value from the columns
7809    var minimumY = Math.min.apply( Math, colGroup );
7810
7811    return {
7812      col: colGroup.indexOf( minimumY ),
7813      y: minimumY,
7814    };
7815  };
7816
7817  /**
7818   * @param {Number} colSpan - number of columns the element spans
7819   * @returns {Array} colGroup
7820   */
7821  proto._getTopColGroup = function( colSpan ) {
7822    if ( colSpan < 2 ) {
7823      // if brick spans only one column, use all the column Ys
7824      return this.colYs;
7825    }
7826
7827    var colGroup = [];
7828    // how many different places could this brick fit horizontally
7829    var groupCount = this.cols + 1 - colSpan;
7830    // for each group potential horizontal position
7831    for ( var i = 0; i < groupCount; i++ ) {
7832      colGroup[i] = this._getColGroupY( i, colSpan );
7833    }
7834    return colGroup;
7835  };
7836
7837  proto._getColGroupY = function( col, colSpan ) {
7838    if ( colSpan < 2 ) {
7839      return this.colYs[ col ];
7840    }
7841    // make an array of colY values for that one group
7842    var groupColYs = this.colYs.slice( col, col + colSpan );
7843    // and get the max value of the array
7844    return Math.max.apply( Math, groupColYs );
7845  };
7846
7847  // get column position based on horizontal index. #873
7848  proto._getHorizontalColPosition = function( colSpan, item ) {
7849    var col = this.horizontalColIndex % this.cols;
7850    var isOver = colSpan > 1 && col + colSpan > this.cols;
7851    // shift to next row if item can't fit on current row
7852    col = isOver ? 0 : col;
7853    // don't let zero-size items take up space
7854    var hasSize = item.size.outerWidth && item.size.outerHeight;
7855    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
7856
7857    return {
7858      col: col,
7859      y: this._getColGroupY( col, colSpan ),
7860    };
7861  };
7862
7863  proto._manageStamp = function( stamp ) {
7864    var stampSize = getSize( stamp );
7865    var offset = this._getElementOffset( stamp );
7866    // get the columns that this stamp affects
7867    var isOriginLeft = this._getOption('originLeft');
7868    var firstX = isOriginLeft ? offset.left : offset.right;
7869    var lastX = firstX + stampSize.outerWidth;
7870    var firstCol = Math.floor( firstX / this.columnWidth );
7871    firstCol = Math.max( 0, firstCol );
7872    var lastCol = Math.floor( lastX / this.columnWidth );
7873    // lastCol should not go over if multiple of columnWidth #425
7874    lastCol -= lastX % this.columnWidth ? 0 : 1;
7875    lastCol = Math.min( this.cols - 1, lastCol );
7876    // set colYs to bottom of the stamp
7877
7878    var isOriginTop = this._getOption('originTop');
7879    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
7880      stampSize.outerHeight;
7881    for ( var i = firstCol; i <= lastCol; i++ ) {
7882      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
7883    }
7884  };
7885
7886  proto._getContainerSize = function() {
7887    this.maxY = Math.max.apply( Math, this.colYs );
7888    var size = {
7889      height: this.maxY
7890    };
7891
7892    if ( this._getOption('fitWidth') ) {
7893      size.width = this._getContainerFitWidth();
7894    }
7895
7896    return size;
7897  };
7898
7899  proto._getContainerFitWidth = function() {
7900    var unusedCols = 0;
7901    // count unused columns
7902    var i = this.cols;
7903    while ( --i ) {
7904      if ( this.colYs[i] !== 0 ) {
7905        break;
7906      }
7907      unusedCols++;
7908    }
7909    // fit container to columns that have been used
7910    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
7911  };
7912
7913  proto.needsResizeLayout = function() {
7914    var previousWidth = this.containerWidth;
7915    this.getContainerWidth();
7916    return previousWidth != this.containerWidth;
7917  };
7918
7919  return Masonry;
7920
7921}));
7922
7923/*!
7924 * Masonry layout mode
7925 * sub-classes Masonry
7926 * https://masonry.desandro.com
7927 */
7928
7929( function( window, factory ) {
7930  // universal module definition
7931  /* jshint strict: false */ /*globals define, module, require */
7932  if ( typeof define == 'function' && define.amd ) {
7933    // AMD
7934    define( 'isotope-layout/js/layout-modes/masonry',[
7935        '../layout-mode',
7936        'masonry-layout/masonry'
7937      ],
7938      factory );
7939  } else if ( typeof module == 'object' && module.exports ) {
7940    // CommonJS
7941    module.exports = factory(
7942      require('../layout-mode'),
7943      require('masonry-layout')
7944    );
7945  } else {
7946    // browser global
7947    factory(
7948      window.Isotope.LayoutMode,
7949      window.Masonry
7950    );
7951  }
7952
7953}( window, function factory( LayoutMode, Masonry ) {
7954'use strict';
7955
7956// -------------------------- masonryDefinition -------------------------- //
7957
7958  // create an Outlayer layout class
7959  var MasonryMode = LayoutMode.create('masonry');
7960
7961  var proto = MasonryMode.prototype;
7962
7963  var keepModeMethods = {
7964    _getElementOffset: true,
7965    layout: true,
7966    _getMeasurement: true
7967  };
7968
7969  // inherit Masonry prototype
7970  for ( var method in Masonry.prototype ) {
7971    // do not inherit mode methods
7972    if ( !keepModeMethods[ method ] ) {
7973      proto[ method ] = Masonry.prototype[ method ];
7974    }
7975  }
7976
7977  var measureColumns = proto.measureColumns;
7978  proto.measureColumns = function() {
7979    // set items, used if measuring first item
7980    this.items = this.isotope.filteredItems;
7981    measureColumns.call( this );
7982  };
7983
7984  // point to mode options for fitWidth
7985  var _getOption = proto._getOption;
7986  proto._getOption = function( option ) {
7987    if ( option == 'fitWidth' ) {
7988      return this.options.isFitWidth !== undefined ?
7989        this.options.isFitWidth : this.options.fitWidth;
7990    }
7991    return _getOption.apply( this.isotope, arguments );
7992  };
7993
7994  return MasonryMode;
7995
7996}));
7997
7998/**
7999 * fitRows layout mode
8000 */
8001
8002( function( window, factory ) {
8003  // universal module definition
8004  /* jshint strict: false */ /*globals define, module, require */
8005  if ( typeof define == 'function' && define.amd ) {
8006    // AMD
8007    define( 'isotope-layout/js/layout-modes/fit-rows',[
8008        '../layout-mode'
8009      ],
8010      factory );
8011  } else if ( typeof exports == 'object' ) {
8012    // CommonJS
8013    module.exports = factory(
8014      require('../layout-mode')
8015    );
8016  } else {
8017    // browser global
8018    factory(
8019      window.Isotope.LayoutMode
8020    );
8021  }
8022
8023}( window, function factory( LayoutMode ) {
8024'use strict';
8025
8026var FitRows = LayoutMode.create('fitRows');
8027
8028var proto = FitRows.prototype;
8029
8030proto._resetLayout = function() {
8031  this.x = 0;
8032  this.y = 0;
8033  this.maxY = 0;
8034  this._getMeasurement( 'gutter', 'outerWidth' );
8035};
8036
8037proto._getItemLayoutPosition = function( item ) {
8038  item.getSize();
8039
8040  var itemWidth = item.size.outerWidth + this.gutter;
8041  // if this element cannot fit in the current row
8042  var containerWidth = this.isotope.size.innerWidth + this.gutter;
8043  if ( this.x !== 0 && itemWidth + this.x > containerWidth ) {
8044    this.x = 0;
8045    this.y = this.maxY;
8046  }
8047
8048  var position = {
8049    x: this.x,
8050    y: this.y
8051  };
8052
8053  this.maxY = Math.max( this.maxY, this.y + item.size.outerHeight );
8054  this.x += itemWidth;
8055
8056  return position;
8057};
8058
8059proto._getContainerSize = function() {
8060  return { height: this.maxY };
8061};
8062
8063return FitRows;
8064
8065}));
8066
8067/**
8068 * vertical layout mode
8069 */
8070
8071( function( window, factory ) {
8072  // universal module definition
8073  /* jshint strict: false */ /*globals define, module, require */
8074  if ( typeof define == 'function' && define.amd ) {
8075    // AMD
8076    define( 'isotope-layout/js/layout-modes/vertical',[
8077        '../layout-mode'
8078      ],
8079      factory );
8080  } else if ( typeof module == 'object' && module.exports ) {
8081    // CommonJS
8082    module.exports = factory(
8083      require('../layout-mode')
8084    );
8085  } else {
8086    // browser global
8087    factory(
8088      window.Isotope.LayoutMode
8089    );
8090  }
8091
8092}( window, function factory( LayoutMode ) {
8093'use strict';
8094
8095var Vertical = LayoutMode.create( 'vertical', {
8096  horizontalAlignment: 0
8097});
8098
8099var proto = Vertical.prototype;
8100
8101proto._resetLayout = function() {
8102  this.y = 0;
8103};
8104
8105proto._getItemLayoutPosition = function( item ) {
8106  item.getSize();
8107  var x = ( this.isotope.size.innerWidth - item.size.outerWidth ) *
8108    this.options.horizontalAlignment;
8109  var y = this.y;
8110  this.y += item.size.outerHeight;
8111  return { x: x, y: y };
8112};
8113
8114proto._getContainerSize = function() {
8115  return { height: this.y };
8116};
8117
8118return Vertical;
8119
8120}));
8121
8122/*!
8123 * Isotope v3.0.6
8124 *
8125 * Licensed GPLv3 for open source use
8126 * or Isotope Commercial License for commercial use
8127 *
8128 * https://isotope.metafizzy.co
8129 * Copyright 2010-2018 Metafizzy
8130 */
8131
8132( function( window, factory ) {
8133  // universal module definition
8134  /* jshint strict: false */ /*globals define, module, require */
8135  if ( typeof define == 'function' && define.amd ) {
8136    // AMD
8137    define( [
8138        'outlayer/outlayer',
8139        'get-size/get-size',
8140        'desandro-matches-selector/matches-selector',
8141        'fizzy-ui-utils/utils',
8142        'isotope-layout/js/item',
8143        'isotope-layout/js/layout-mode',
8144        // include default layout modes
8145        'isotope-layout/js/layout-modes/masonry',
8146        'isotope-layout/js/layout-modes/fit-rows',
8147        'isotope-layout/js/layout-modes/vertical'
8148      ],
8149      function( Outlayer, getSize, matchesSelector, utils, Item, LayoutMode ) {
8150        return factory( window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode );
8151      });
8152  } else if ( typeof module == 'object' && module.exports ) {
8153    // CommonJS
8154    module.exports = factory(
8155      window,
8156      require('outlayer'),
8157      require('get-size'),
8158      require('desandro-matches-selector'),
8159      require('fizzy-ui-utils'),
8160      require('isotope-layout/js/item'),
8161      require('isotope-layout/js/layout-mode'),
8162      // include default layout modes
8163      require('isotope-layout/js/layout-modes/masonry'),
8164      require('isotope-layout/js/layout-modes/fit-rows'),
8165      require('isotope-layout/js/layout-modes/vertical')
8166    );
8167  } else {
8168    // browser global
8169    window.Isotope = factory(
8170      window,
8171      window.Outlayer,
8172      window.getSize,
8173      window.matchesSelector,
8174      window.fizzyUIUtils,
8175      window.Isotope.Item,
8176      window.Isotope.LayoutMode
8177    );
8178  }
8179
8180}( window, function factory( window, Outlayer, getSize, matchesSelector, utils,
8181  Item, LayoutMode ) {
8182
8183
8184
8185// -------------------------- vars -------------------------- //
8186
8187var jQuery = window.jQuery;
8188
8189// -------------------------- helpers -------------------------- //
8190
8191var trim = String.prototype.trim ?
8192  function( str ) {
8193    return str.trim();
8194  } :
8195  function( str ) {
8196    return str.replace( /^\s+|\s+$/g, '' );
8197  };
8198
8199// -------------------------- isotopeDefinition -------------------------- //
8200
8201  // create an Outlayer layout class
8202  var Isotope = Outlayer.create( 'isotope', {
8203    layoutMode: 'masonry',
8204    isJQueryFiltering: true,
8205    sortAscending: true
8206  });
8207
8208  Isotope.Item = Item;
8209  Isotope.LayoutMode = LayoutMode;
8210
8211  var proto = Isotope.prototype;
8212
8213  proto._create = function() {
8214    this.itemGUID = 0;
8215    // functions that sort items
8216    this._sorters = {};
8217    this._getSorters();
8218    // call super
8219    Outlayer.prototype._create.call( this );
8220
8221    // create layout modes
8222    this.modes = {};
8223    // start filteredItems with all items
8224    this.filteredItems = this.items;
8225    // keep of track of sortBys
8226    this.sortHistory = [ 'original-order' ];
8227    // create from registered layout modes
8228    for ( var name in LayoutMode.modes ) {
8229      this._initLayoutMode( name );
8230    }
8231  };
8232
8233  proto.reloadItems = function() {
8234    // reset item ID counter
8235    this.itemGUID = 0;
8236    // call super
8237    Outlayer.prototype.reloadItems.call( this );
8238  };
8239
8240  proto._itemize = function() {
8241    var items = Outlayer.prototype._itemize.apply( this, arguments );
8242    // assign ID for original-order
8243    for ( var i=0; i < items.length; i++ ) {
8244      var item = items[i];
8245      item.id = this.itemGUID++;
8246    }
8247    this._updateItemsSortData( items );
8248    return items;
8249  };
8250
8251
8252  // -------------------------- layout -------------------------- //
8253
8254  proto._initLayoutMode = function( name ) {
8255    var Mode = LayoutMode.modes[ name ];
8256    // set mode options
8257    // HACK extend initial options, back-fill in default options
8258    var initialOpts = this.options[ name ] || {};
8259    this.options[ name ] = Mode.options ?
8260      utils.extend( Mode.options, initialOpts ) : initialOpts;
8261    // init layout mode instance
8262    this.modes[ name ] = new Mode( this );
8263  };
8264
8265
8266  proto.layout = function() {
8267    // if first time doing layout, do all magic
8268    if ( !this._isLayoutInited && this._getOption('initLayout') ) {
8269      this.arrange();
8270      return;
8271    }
8272    this._layout();
8273  };
8274
8275  // private method to be used in layout() & magic()
8276  proto._layout = function() {
8277    // don't animate first layout
8278    var isInstant = this._getIsInstant();
8279    // layout flow
8280    this._resetLayout();
8281    this._manageStamps();
8282    this.layoutItems( this.filteredItems, isInstant );
8283
8284    // flag for initalized
8285    this._isLayoutInited = true;
8286  };
8287
8288  // filter + sort + layout
8289  proto.arrange = function( opts ) {
8290    // set any options pass
8291    this.option( opts );
8292    this._getIsInstant();
8293    // filter, sort, and layout
8294
8295    // filter
8296    var filtered = this._filter( this.items );
8297    this.filteredItems = filtered.matches;
8298
8299    this._bindArrangeComplete();
8300
8301    if ( this._isInstant ) {
8302      this._noTransition( this._hideReveal, [ filtered ] );
8303    } else {
8304      this._hideReveal( filtered );
8305    }
8306
8307    this._sort();
8308    this._layout();
8309  };
8310  // alias to _init for main plugin method
8311  proto._init = proto.arrange;
8312
8313  proto._hideReveal = function( filtered ) {
8314    this.reveal( filtered.needReveal );
8315    this.hide( filtered.needHide );
8316  };
8317
8318  // HACK
8319  // Don't animate/transition first layout
8320  // Or don't animate/transition other layouts
8321  proto._getIsInstant = function() {
8322    var isLayoutInstant = this._getOption('layoutInstant');
8323    var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
8324      !this._isLayoutInited;
8325    this._isInstant = isInstant;
8326    return isInstant;
8327  };
8328
8329  // listen for layoutComplete, hideComplete and revealComplete
8330  // to trigger arrangeComplete
8331  proto._bindArrangeComplete = function() {
8332    // listen for 3 events to trigger arrangeComplete
8333    var isLayoutComplete, isHideComplete, isRevealComplete;
8334    var _this = this;
8335    function arrangeParallelCallback() {
8336      if ( isLayoutComplete && isHideComplete && isRevealComplete ) {
8337        _this.dispatchEvent( 'arrangeComplete', null, [ _this.filteredItems ] );
8338      }
8339    }
8340    this.once( 'layoutComplete', function() {
8341      isLayoutComplete = true;
8342      arrangeParallelCallback();
8343    });
8344    this.once( 'hideComplete', function() {
8345      isHideComplete = true;
8346      arrangeParallelCallback();
8347    });
8348    this.once( 'revealComplete', function() {
8349      isRevealComplete = true;
8350      arrangeParallelCallback();
8351    });
8352  };
8353
8354  // -------------------------- filter -------------------------- //
8355
8356  proto._filter = function( items ) {
8357    var filter = this.options.filter;
8358    filter = filter || '*';
8359    var matches = [];
8360    var hiddenMatched = [];
8361    var visibleUnmatched = [];
8362
8363    var test = this._getFilterTest( filter );
8364
8365    // test each item
8366    for ( var i=0; i < items.length; i++ ) {
8367      var item = items[i];
8368      if ( item.isIgnored ) {
8369        continue;
8370      }
8371      // add item to either matched or unmatched group
8372      var isMatched = test( item );
8373      // item.isFilterMatched = isMatched;
8374      // add to matches if its a match
8375      if ( isMatched ) {
8376        matches.push( item );
8377      }
8378      // add to additional group if item needs to be hidden or revealed
8379      if ( isMatched && item.isHidden ) {
8380        hiddenMatched.push( item );
8381      } else if ( !isMatched && !item.isHidden ) {
8382        visibleUnmatched.push( item );
8383      }
8384    }
8385
8386    // return collections of items to be manipulated
8387    return {
8388      matches: matches,
8389      needReveal: hiddenMatched,
8390      needHide: visibleUnmatched
8391    };
8392  };
8393
8394  // get a jQuery, function, or a matchesSelector test given the filter
8395  proto._getFilterTest = function( filter ) {
8396    if ( jQuery && this.options.isJQueryFiltering ) {
8397      // use jQuery
8398      return function( item ) {
8399        return jQuery( item.element ).is( filter );
8400      };
8401    }
8402    if ( typeof filter == 'function' ) {
8403      // use filter as function
8404      return function( item ) {
8405        return filter( item.element );
8406      };
8407    }
8408    // default, use filter as selector string
8409    return function( item ) {
8410      return matchesSelector( item.element, filter );
8411    };
8412  };
8413
8414  // -------------------------- sorting -------------------------- //
8415
8416  /**
8417   * @params {Array} elems
8418   * @public
8419   */
8420  proto.updateSortData = function( elems ) {
8421    // get items
8422    var items;
8423    if ( elems ) {
8424      elems = utils.makeArray( elems );
8425      items = this.getItems( elems );
8426    } else {
8427      // update all items if no elems provided
8428      items = this.items;
8429    }
8430
8431    this._getSorters();
8432    this._updateItemsSortData( items );
8433  };
8434
8435  proto._getSorters = function() {
8436    var getSortData = this.options.getSortData;
8437    for ( var key in getSortData ) {
8438      var sorter = getSortData[ key ];
8439      this._sorters[ key ] = mungeSorter( sorter );
8440    }
8441  };
8442
8443  /**
8444   * @params {Array} items - of Isotope.Items
8445   * @private
8446   */
8447  proto._updateItemsSortData = function( items ) {
8448    // do not update if no items
8449    var len = items && items.length;
8450
8451    for ( var i=0; len && i < len; i++ ) {
8452      var item = items[i];
8453      item.updateSortData();
8454    }
8455  };
8456
8457  // ----- munge sorter ----- //
8458
8459  // encapsulate this, as we just need mungeSorter
8460  // other functions in here are just for munging
8461  var mungeSorter = ( function() {
8462    // add a magic layer to sorters for convienent shorthands
8463    // `.foo-bar` will use the text of .foo-bar querySelector
8464    // `[foo-bar]` will use attribute
8465    // you can also add parser
8466    // `.foo-bar parseInt` will parse that as a number
8467    function mungeSorter( sorter ) {
8468      // if not a string, return function or whatever it is
8469      if ( typeof sorter != 'string' ) {
8470        return sorter;
8471      }
8472      // parse the sorter string
8473      var args = trim( sorter ).split(' ');
8474      var query = args[0];
8475      // check if query looks like [an-attribute]
8476      var attrMatch = query.match( /^\[(.+)\]$/ );
8477      var attr = attrMatch && attrMatch[1];
8478      var getValue = getValueGetter( attr, query );
8479      // use second argument as a parser
8480      var parser = Isotope.sortDataParsers[ args[1] ];
8481      // parse the value, if there was a parser
8482      sorter = parser ? function( elem ) {
8483        return elem && parser( getValue( elem ) );
8484      } :
8485      // otherwise just return value
8486      function( elem ) {
8487        return elem && getValue( elem );
8488      };
8489
8490      return sorter;
8491    }
8492
8493    // get an attribute getter, or get text of the querySelector
8494    function getValueGetter( attr, query ) {
8495      // if query looks like [foo-bar], get attribute
8496      if ( attr ) {
8497        return function getAttribute( elem ) {
8498          return elem.getAttribute( attr );
8499        };
8500      }
8501
8502      // otherwise, assume its a querySelector, and get its text
8503      return function getChildText( elem ) {
8504        var child = elem.querySelector( query );
8505        return child && child.textContent;
8506      };
8507    }
8508
8509    return mungeSorter;
8510  })();
8511
8512  // parsers used in getSortData shortcut strings
8513  Isotope.sortDataParsers = {
8514    'parseInt': function( val ) {
8515      return parseInt( val, 10 );
8516    },
8517    'parseFloat': function( val ) {
8518      return parseFloat( val );
8519    }
8520  };
8521
8522  // ----- sort method ----- //
8523
8524  // sort filteredItem order
8525  proto._sort = function() {
8526    if ( !this.options.sortBy ) {
8527      return;
8528    }
8529    // keep track of sortBy History
8530    var sortBys = utils.makeArray( this.options.sortBy );
8531    if ( !this._getIsSameSortBy( sortBys ) ) {
8532      // concat all sortBy and sortHistory, add to front, oldest goes in last
8533      this.sortHistory = sortBys.concat( this.sortHistory );
8534    }
8535    // sort magic
8536    var itemSorter = getItemSorter( this.sortHistory, this.options.sortAscending );
8537    this.filteredItems.sort( itemSorter );
8538  };
8539
8540  // check if sortBys is same as start of sortHistory
8541  proto._getIsSameSortBy = function( sortBys ) {
8542    for ( var i=0; i < sortBys.length; i++ ) {
8543      if ( sortBys[i] != this.sortHistory[i] ) {
8544        return false;
8545      }
8546    }
8547    return true;
8548  };
8549
8550  // returns a function used for sorting
8551  function getItemSorter( sortBys, sortAsc ) {
8552    return function sorter( itemA, itemB ) {
8553      // cycle through all sortKeys
8554      for ( var i = 0; i < sortBys.length; i++ ) {
8555        var sortBy = sortBys[i];
8556        var a = itemA.sortData[ sortBy ];
8557        var b = itemB.sortData[ sortBy ];
8558        if ( a > b || a < b ) {
8559          // if sortAsc is an object, use the value given the sortBy key
8560          var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
8561          var direction = isAscending ? 1 : -1;
8562          return ( a > b ? 1 : -1 ) * direction;
8563        }
8564      }
8565      return 0;
8566    };
8567  }
8568
8569  // -------------------------- methods -------------------------- //
8570
8571  // get layout mode
8572  proto._mode = function() {
8573    var layoutMode = this.options.layoutMode;
8574    var mode = this.modes[ layoutMode ];
8575    if ( !mode ) {
8576      // TODO console.error
8577      throw new Error( 'No layout mode: ' + layoutMode );
8578    }
8579    // HACK sync mode's options
8580    // any options set after init for layout mode need to be synced
8581    mode.options = this.options[ layoutMode ];
8582    return mode;
8583  };
8584
8585  proto._resetLayout = function() {
8586    // trigger original reset layout
8587    Outlayer.prototype._resetLayout.call( this );
8588    this._mode()._resetLayout();
8589  };
8590
8591  proto._getItemLayoutPosition = function( item  ) {
8592    return this._mode()._getItemLayoutPosition( item );
8593  };
8594
8595  proto._manageStamp = function( stamp ) {
8596    this._mode()._manageStamp( stamp );
8597  };
8598
8599  proto._getContainerSize = function() {
8600    return this._mode()._getContainerSize();
8601  };
8602
8603  proto.needsResizeLayout = function() {
8604    return this._mode().needsResizeLayout();
8605  };
8606
8607  // -------------------------- adding & removing -------------------------- //
8608
8609  // HEADS UP overwrites default Outlayer appended
8610  proto.appended = function( elems ) {
8611    var items = this.addItems( elems );
8612    if ( !items.length ) {
8613      return;
8614    }
8615    // filter, layout, reveal new items
8616    var filteredItems = this._filterRevealAdded( items );
8617    // add to filteredItems
8618    this.filteredItems = this.filteredItems.concat( filteredItems );
8619  };
8620
8621  // HEADS UP overwrites default Outlayer prepended
8622  proto.prepended = function( elems ) {
8623    var items = this._itemize( elems );
8624    if ( !items.length ) {
8625      return;
8626    }
8627    // start new layout
8628    this._resetLayout();
8629    this._manageStamps();
8630    // filter, layout, reveal new items
8631    var filteredItems = this._filterRevealAdded( items );
8632    // layout previous items
8633    this.layoutItems( this.filteredItems );
8634    // add to items and filteredItems
8635    this.filteredItems = filteredItems.concat( this.filteredItems );
8636    this.items = items.concat( this.items );
8637  };
8638
8639  proto._filterRevealAdded = function( items ) {
8640    var filtered = this._filter( items );
8641    this.hide( filtered.needHide );
8642    // reveal all new items
8643    this.reveal( filtered.matches );
8644    // layout new items, no transition
8645    this.layoutItems( filtered.matches, true );
8646    return filtered.matches;
8647  };
8648
8649  /**
8650   * Filter, sort, and layout newly-appended item elements
8651   * @param {Array or NodeList or Element} elems
8652   */
8653  proto.insert = function( elems ) {
8654    var items = this.addItems( elems );
8655    if ( !items.length ) {
8656      return;
8657    }
8658    // append item elements
8659    var i, item;
8660    var len = items.length;
8661    for ( i=0; i < len; i++ ) {
8662      item = items[i];
8663      this.element.appendChild( item.element );
8664    }
8665    // filter new stuff
8666    var filteredInsertItems = this._filter( items ).matches;
8667    // set flag
8668    for ( i=0; i < len; i++ ) {
8669      items[i].isLayoutInstant = true;
8670    }
8671    this.arrange();
8672    // reset flag
8673    for ( i=0; i < len; i++ ) {
8674      delete items[i].isLayoutInstant;
8675    }
8676    this.reveal( filteredInsertItems );
8677  };
8678
8679  var _remove = proto.remove;
8680  proto.remove = function( elems ) {
8681    elems = utils.makeArray( elems );
8682    var removeItems = this.getItems( elems );
8683    // do regular thing
8684    _remove.call( this, elems );
8685    // bail if no items to remove
8686    var len = removeItems && removeItems.length;
8687    // remove elems from filteredItems
8688    for ( var i=0; len && i < len; i++ ) {
8689      var item = removeItems[i];
8690      // remove item from collection
8691      utils.removeFrom( this.filteredItems, item );
8692    }
8693  };
8694
8695  proto.shuffle = function() {
8696    // update random sortData
8697    for ( var i=0; i < this.items.length; i++ ) {
8698      var item = this.items[i];
8699      item.sortData.random = Math.random();
8700    }
8701    this.options.sortBy = 'random';
8702    this._sort();
8703    this._layout();
8704  };
8705
8706  /**
8707   * trigger fn without transition
8708   * kind of hacky to have this in the first place
8709   * @param {Function} fn
8710   * @param {Array} args
8711   * @returns ret
8712   * @private
8713   */
8714  proto._noTransition = function( fn, args ) {
8715    // save transitionDuration before disabling
8716    var transitionDuration = this.options.transitionDuration;
8717    // disable transition
8718    this.options.transitionDuration = 0;
8719    // do it
8720    var returnValue = fn.apply( this, args );
8721    // re-enable transition for reveal
8722    this.options.transitionDuration = transitionDuration;
8723    return returnValue;
8724  };
8725
8726  // ----- helper methods ----- //
8727
8728  /**
8729   * getter method for getting filtered item elements
8730   * @returns {Array} elems - collection of item elements
8731   */
8732  proto.getFilteredItemElements = function() {
8733    return this.filteredItems.map( function( item ) {
8734      return item.element;
8735    });
8736  };
8737
8738  // -----  ----- //
8739
8740  return Isotope;
8741
8742}));
8743
vendor: 29,252 bytes, lines 8744-9900
8744/*!
8745 * Packery layout mode PACKAGED v2.0.1
8746 * sub-classes Packery
8747 */
8748
8749/**
8750 * Rect
8751 * low-level utility class for basic geometry
8752 */
8753
8754( function( window, factory ) {
8755  // universal module definition
8756  /* jshint strict: false */ /* globals define, module */
8757  if ( typeof define == 'function' && define.amd ) {
8758    // AMD
8759    define( 'packery/js/rect',factory );
8760  } else if ( typeof module == 'object' && module.exports ) {
8761    // CommonJS
8762    module.exports = factory();
8763  } else {
8764    // browser global
8765    window.Packery = window.Packery || {};
8766    window.Packery.Rect = factory();
8767  }
8768
8769}( window, function factory() {
8770
8771
8772// -------------------------- Rect -------------------------- //
8773
8774function Rect( props ) {
8775  // extend properties from defaults
8776  for ( var prop in Rect.defaults ) {
8777    this[ prop ] = Rect.defaults[ prop ];
8778  }
8779
8780  for ( prop in props ) {
8781    this[ prop ] = props[ prop ];
8782  }
8783
8784}
8785
8786Rect.defaults = {
8787  x: 0,
8788  y: 0,
8789  width: 0,
8790  height: 0
8791};
8792
8793var proto = Rect.prototype;
8794
8795/**
8796 * Determines whether or not this rectangle wholly encloses another rectangle or point.
8797 * @param {Rect} rect
8798 * @returns {Boolean}
8799**/
8800proto.contains = function( rect ) {
8801  // points don't have width or height
8802  var otherWidth = rect.width || 0;
8803  var otherHeight = rect.height || 0;
8804  return this.x <= rect.x &&
8805    this.y <= rect.y &&
8806    this.x + this.width >= rect.x + otherWidth &&
8807    this.y + this.height >= rect.y + otherHeight;
8808};
8809
8810/**
8811 * Determines whether or not the rectangle intersects with another.
8812 * @param {Rect} rect
8813 * @returns {Boolean}
8814**/
8815proto.overlaps = function( rect ) {
8816  var thisRight = this.x + this.width;
8817  var thisBottom = this.y + this.height;
8818  var rectRight = rect.x + rect.width;
8819  var rectBottom = rect.y + rect.height;
8820
8821  // http://stackoverflow.com/a/306332
8822  return this.x < rectRight &&
8823    thisRight > rect.x &&
8824    this.y < rectBottom &&
8825    thisBottom > rect.y;
8826};
8827
8828/**
8829 * @param {Rect} rect - the overlapping rect
8830 * @returns {Array} freeRects - rects representing the area around the rect
8831**/
8832proto.getMaximalFreeRects = function( rect ) {
8833
8834  // if no intersection, return false
8835  if ( !this.overlaps( rect ) ) {
8836    return false;
8837  }
8838
8839  var freeRects = [];
8840  var freeRect;
8841
8842  var thisRight = this.x + this.width;
8843  var thisBottom = this.y + this.height;
8844  var rectRight = rect.x + rect.width;
8845  var rectBottom = rect.y + rect.height;
8846
8847  // top
8848  if ( this.y < rect.y ) {
8849    freeRect = new Rect({
8850      x: this.x,
8851      y: this.y,
8852      width: this.width,
8853      height: rect.y - this.y
8854    });
8855    freeRects.push( freeRect );
8856  }
8857
8858  // right
8859  if ( thisRight > rectRight ) {
8860    freeRect = new Rect({
8861      x: rectRight,
8862      y: this.y,
8863      width: thisRight - rectRight,
8864      height: this.height
8865    });
8866    freeRects.push( freeRect );
8867  }
8868
8869  // bottom
8870  if ( thisBottom > rectBottom ) {
8871    freeRect = new Rect({
8872      x: this.x,
8873      y: rectBottom,
8874      width: this.width,
8875      height: thisBottom - rectBottom
8876    });
8877    freeRects.push( freeRect );
8878  }
8879
8880  // left
8881  if ( this.x < rect.x ) {
8882    freeRect = new Rect({
8883      x: this.x,
8884      y: this.y,
8885      width: rect.x - this.x,
8886      height: this.height
8887    });
8888    freeRects.push( freeRect );
8889  }
8890
8891  return freeRects;
8892};
8893
8894proto.canFit = function( rect ) {
8895  return this.width >= rect.width && this.height >= rect.height;
8896};
8897
8898return Rect;
8899
8900}));
8901
8902/**
8903 * Packer
8904 * bin-packing algorithm
8905 */
8906
8907( function( window, factory ) {
8908  // universal module definition
8909  /* jshint strict: false */ /* globals define, module, require */
8910  if ( typeof define == 'function' && define.amd ) {
8911    // AMD
8912    define( 'packery/js/packer',[ './rect' ], factory );
8913  } else if ( typeof module == 'object' && module.exports ) {
8914    // CommonJS
8915    module.exports = factory(
8916      require('./rect')
8917    );
8918  } else {
8919    // browser global
8920    var Packery = window.Packery = window.Packery || {};
8921    Packery.Packer = factory( Packery.Rect );
8922  }
8923
8924}( window, function factory( Rect ) {
8925
8926
8927// -------------------------- Packer -------------------------- //
8928
8929/**
8930 * @param {Number} width
8931 * @param {Number} height
8932 * @param {String} sortDirection
8933 *   topLeft for vertical, leftTop for horizontal
8934 */
8935function Packer( width, height, sortDirection ) {
8936  this.width = width || 0;
8937  this.height = height || 0;
8938  this.sortDirection = sortDirection || 'downwardLeftToRight';
8939
8940  this.reset();
8941}
8942
8943var proto = Packer.prototype;
8944
8945proto.reset = function() {
8946  this.spaces = [];
8947
8948  var initialSpace = new Rect({
8949    x: 0,
8950    y: 0,
8951    width: this.width,
8952    height: this.height
8953  });
8954
8955  this.spaces.push( initialSpace );
8956  // set sorter
8957  this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
8958};
8959
8960// change x and y of rect to fit with in Packer's available spaces
8961proto.pack = function( rect ) {
8962  for ( var i=0; i < this.spaces.length; i++ ) {
8963    var space = this.spaces[i];
8964    if ( space.canFit( rect ) ) {
8965      this.placeInSpace( rect, space );
8966      break;
8967    }
8968  }
8969};
8970
8971proto.columnPack = function( rect ) {
8972  for ( var i=0; i < this.spaces.length; i++ ) {
8973    var space = this.spaces[i];
8974    var canFitInSpaceColumn = space.x <= rect.x &&
8975      space.x + space.width >= rect.x + rect.width &&
8976      space.height >= rect.height - 0.01; // fudge number for rounding error
8977    if ( canFitInSpaceColumn ) {
8978      rect.y = space.y;
8979      this.placed( rect );
8980      break;
8981    }
8982  }
8983};
8984
8985proto.rowPack = function( rect ) {
8986  for ( var i=0; i < this.spaces.length; i++ ) {
8987    var space = this.spaces[i];
8988    var canFitInSpaceRow = space.y <= rect.y &&
8989      space.y + space.height >= rect.y + rect.height &&
8990      space.width >= rect.width - 0.01; // fudge number for rounding error
8991    if ( canFitInSpaceRow ) {
8992      rect.x = space.x;
8993      this.placed( rect );
8994      break;
8995    }
8996  }
8997};
8998
8999proto.placeInSpace = function( rect, space ) {
9000  // place rect in space
9001  rect.x = space.x;
9002  rect.y = space.y;
9003
9004  this.placed( rect );
9005};
9006
9007// update spaces with placed rect
9008proto.placed = function( rect ) {
9009  // update spaces
9010  var revisedSpaces = [];
9011  for ( var i=0; i < this.spaces.length; i++ ) {
9012    var space = this.spaces[i];
9013    var newSpaces = space.getMaximalFreeRects( rect );
9014    // add either the original space or the new spaces to the revised spaces
9015    if ( newSpaces ) {
9016      revisedSpaces.push.apply( revisedSpaces, newSpaces );
9017    } else {
9018      revisedSpaces.push( space );
9019    }
9020  }
9021
9022  this.spaces = revisedSpaces;
9023
9024  this.mergeSortSpaces();
9025};
9026
9027proto.mergeSortSpaces = function() {
9028  // remove redundant spaces
9029  Packer.mergeRects( this.spaces );
9030  this.spaces.sort( this.sorter );
9031};
9032
9033// add a space back
9034proto.addSpace = function( rect ) {
9035  this.spaces.push( rect );
9036  this.mergeSortSpaces();
9037};
9038
9039// -------------------------- utility functions -------------------------- //
9040
9041/**
9042 * Remove redundant rectangle from array of rectangles
9043 * @param {Array} rects: an array of Rects
9044 * @returns {Array} rects: an array of Rects
9045**/
9046Packer.mergeRects = function( rects ) {
9047  var i = 0;
9048  var rect = rects[i];
9049
9050  rectLoop:
9051  while ( rect ) {
9052    var j = 0;
9053    var compareRect = rects[ i + j ];
9054
9055    while ( compareRect ) {
9056      if  ( compareRect == rect ) {
9057        j++; // next
9058      } else if ( compareRect.contains( rect ) ) {
9059        // remove rect
9060        rects.splice( i, 1 );
9061        rect = rects[i]; // set next rect
9062        continue rectLoop; // bail on compareLoop
9063      } else if ( rect.contains( compareRect ) ) {
9064        // remove compareRect
9065        rects.splice( i + j, 1 );
9066      } else {
9067        j++;
9068      }
9069      compareRect = rects[ i + j ]; // set next compareRect
9070    }
9071    i++;
9072    rect = rects[i];
9073  }
9074
9075  return rects;
9076};
9077
9078
9079// -------------------------- sorters -------------------------- //
9080
9081// functions for sorting rects in order
9082var sorters = {
9083  // top down, then left to right
9084  downwardLeftToRight: function( a, b ) {
9085    return a.y - b.y || a.x - b.x;
9086  },
9087  // left to right, then top down
9088  rightwardTopToBottom: function( a, b ) {
9089    return a.x - b.x || a.y - b.y;
9090  }
9091};
9092
9093
9094// --------------------------  -------------------------- //
9095
9096return Packer;
9097
9098}));
9099
9100/**
9101 * Packery Item Element
9102**/
9103
9104( function( window, factory ) {
9105  // universal module definition
9106  /* jshint strict: false */ /* globals define, module, require */
9107  if ( typeof define == 'function' && define.amd ) {
9108    // AMD
9109    define( 'packery/js/item',[
9110        'outlayer/outlayer',
9111        './rect'
9112      ],
9113      factory );
9114  } else if ( typeof module == 'object' && module.exports ) {
9115    // CommonJS
9116    module.exports = factory(
9117      require('outlayer'),
9118      require('./rect')
9119    );
9120  } else {
9121    // browser global
9122    window.Packery.Item = factory(
9123      window.Outlayer,
9124      window.Packery.Rect
9125    );
9126  }
9127
9128}( window, function factory( Outlayer, Rect ) {
9129
9130
9131// -------------------------- Item -------------------------- //
9132
9133var docElemStyle = document.documentElement.style;
9134
9135var transformProperty = typeof docElemStyle.transform == 'string' ?
9136  'transform' : 'WebkitTransform';
9137
9138// sub-class Item
9139var Item = function PackeryItem() {
9140  Outlayer.Item.apply( this, arguments );
9141};
9142
9143var proto = Item.prototype = Object.create( Outlayer.Item.prototype );
9144
9145var __create = proto._create;
9146proto._create = function() {
9147  // call default _create logic
9148  __create.call( this );
9149  this.rect = new Rect();
9150};
9151
9152var _moveTo = proto.moveTo;
9153proto.moveTo = function( x, y ) {
9154  // don't shift 1px while dragging
9155  var dx = Math.abs( this.position.x - x );
9156  var dy = Math.abs( this.position.y - y );
9157
9158  var canHackGoTo = this.layout.dragItemCount && !this.isPlacing &&
9159    !this.isTransitioning && dx < 1 && dy < 1;
9160  if ( canHackGoTo ) {
9161    this.goTo( x, y );
9162    return;
9163  }
9164  _moveTo.apply( this, arguments );
9165};
9166
9167// -------------------------- placing -------------------------- //
9168
9169proto.enablePlacing = function() {
9170  this.removeTransitionStyles();
9171  // remove transform property from transition
9172  if ( this.isTransitioning && transformProperty ) {
9173    this.element.style[ transformProperty ] = 'none';
9174  }
9175  this.isTransitioning = false;
9176  this.getSize();
9177  this.layout._setRectSize( this.element, this.rect );
9178  this.isPlacing = true;
9179};
9180
9181proto.disablePlacing = function() {
9182  this.isPlacing = false;
9183};
9184
9185// -----  ----- //
9186
9187// remove element from DOM
9188proto.removeElem = function() {
9189  this.element.parentNode.removeChild( this.element );
9190  // add space back to packer
9191  this.layout.packer.addSpace( this.rect );
9192  this.emitEvent( 'remove', [ this ] );
9193};
9194
9195// ----- dropPlaceholder ----- //
9196
9197proto.showDropPlaceholder = function() {
9198  var dropPlaceholder = this.dropPlaceholder;
9199  if ( !dropPlaceholder ) {
9200    // create dropPlaceholder
9201    dropPlaceholder = this.dropPlaceholder = document.createElement('div');
9202    dropPlaceholder.className = 'packery-drop-placeholder';
9203    dropPlaceholder.style.position = 'absolute';
9204  }
9205
9206  dropPlaceholder.style.width = this.size.width + 'px';
9207  dropPlaceholder.style.height = this.size.height + 'px';
9208  this.positionDropPlaceholder();
9209  this.layout.element.appendChild( dropPlaceholder );
9210};
9211
9212proto.positionDropPlaceholder = function() {
9213  this.dropPlaceholder.style[ transformProperty ] = 'translate(' +
9214    this.rect.x + 'px, ' + this.rect.y + 'px)';
9215};
9216
9217proto.hideDropPlaceholder = function() {
9218  this.layout.element.removeChild( this.dropPlaceholder );
9219};
9220
9221// -----  ----- //
9222
9223return Item;
9224
9225}));
9226
9227/*!
9228 * Packery v2.0.0
9229 * Gapless, draggable grid layouts
9230 *
9231 * Licensed GPLv3 for open source use
9232 * or Packery Commercial License for commercial use
9233 *
9234 * http://packery.metafizzy.co
9235 * Copyright 2016 Metafizzy
9236 */
9237
9238( function( window, factory ) {
9239  // universal module definition
9240  /* jshint strict: false */ /* globals define, module, require */
9241  if ( typeof define == 'function' && define.amd ) {
9242    // AMD
9243    define( 'packery/js/packery',[
9244        'get-size/get-size',
9245        'outlayer/outlayer',
9246        './rect',
9247        './packer',
9248        './item'
9249      ],
9250      factory );
9251  } else if ( typeof module == 'object' && module.exports ) {
9252    // CommonJS
9253    module.exports = factory(
9254      require('get-size'),
9255      require('outlayer'),
9256      require('./rect'),
9257      require('./packer'),
9258      require('./item')
9259    );
9260  } else {
9261    // browser global
9262    window.Packery = factory(
9263      window.getSize,
9264      window.Outlayer,
9265      window.Packery.Rect,
9266      window.Packery.Packer,
9267      window.Packery.Item
9268    );
9269  }
9270
9271}( window, function factory( getSize, Outlayer, Rect, Packer, Item ) {
9272
9273
9274// ----- Rect ----- //
9275
9276// allow for pixel rounding errors IE8-IE11 & Firefox; #227
9277Rect.prototype.canFit = function( rect ) {
9278  return this.width >= rect.width - 1 && this.height >= rect.height - 1;
9279};
9280
9281// -------------------------- Packery -------------------------- //
9282
9283// create an Outlayer layout class
9284var Packery = Outlayer.create('packery');
9285Packery.Item = Item;
9286
9287var proto = Packery.prototype;
9288
9289proto._create = function() {
9290  // call super
9291  Outlayer.prototype._create.call( this );
9292
9293  // initial properties
9294  this.packer = new Packer();
9295  // packer for drop targets
9296  this.shiftPacker = new Packer();
9297  this.isEnabled = true;
9298
9299  this.dragItemCount = 0;
9300
9301  // create drag handlers
9302  var _this = this;
9303  this.handleDraggabilly = {
9304    dragStart: function() {
9305      _this.itemDragStart( this.element );
9306    },
9307    dragMove: function() {
9308      _this.itemDragMove( this.element, this.position.x, this.position.y );
9309    },
9310    dragEnd: function() {
9311      _this.itemDragEnd( this.element );
9312    }
9313  };
9314
9315  this.handleUIDraggable = {
9316    start: function handleUIDraggableStart( event, ui ) {
9317      // HTML5 may trigger dragstart, dismiss HTML5 dragging
9318      if ( !ui ) {
9319        return;
9320      }
9321      _this.itemDragStart( event.currentTarget );
9322    },
9323    drag: function handleUIDraggableDrag( event, ui ) {
9324      if ( !ui ) {
9325        return;
9326      }
9327      _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
9328    },
9329    stop: function handleUIDraggableStop( event, ui ) {
9330      if ( !ui ) {
9331        return;
9332      }
9333      _this.itemDragEnd( event.currentTarget );
9334    }
9335  };
9336
9337};
9338
9339
9340// ----- init & layout ----- //
9341
9342/**
9343 * logic before any new layout
9344 */
9345proto._resetLayout = function() {
9346  this.getSize();
9347
9348  this._getMeasurements();
9349
9350  // reset packer
9351  var width, height, sortDirection;
9352  // packer settings, if horizontal or vertical
9353  if ( this._getOption('horizontal') ) {
9354    width = Infinity;
9355    height = this.size.innerHeight + this.gutter;
9356    sortDirection = 'rightwardTopToBottom';
9357  } else {
9358    width = this.size.innerWidth + this.gutter;
9359    height = Infinity;
9360    sortDirection = 'downwardLeftToRight';
9361  }
9362
9363  this.packer.width = this.shiftPacker.width = width;
9364  this.packer.height = this.shiftPacker.height = height;
9365  this.packer.sortDirection = this.shiftPacker.sortDirection = sortDirection;
9366
9367  this.packer.reset();
9368
9369  // layout
9370  this.maxY = 0;
9371  this.maxX = 0;
9372};
9373
9374/**
9375 * update columnWidth, rowHeight, & gutter
9376 * @private
9377 */
9378proto._getMeasurements = function() {
9379  this._getMeasurement( 'columnWidth', 'width' );
9380  this._getMeasurement( 'rowHeight', 'height' );
9381  this._getMeasurement( 'gutter', 'width' );
9382};
9383
9384proto._getItemLayoutPosition = function( item ) {
9385  this._setRectSize( item.element, item.rect );
9386  if ( this.isShifting || this.dragItemCount > 0 ) {
9387    var packMethod = this._getPackMethod();
9388    this.packer[ packMethod ]( item.rect );
9389  } else {
9390    this.packer.pack( item.rect );
9391  }
9392
9393  this._setMaxXY( item.rect );
9394  return item.rect;
9395};
9396
9397proto.shiftLayout = function() {
9398  this.isShifting = true;
9399  this.layout();
9400  delete this.isShifting;
9401};
9402
9403proto._getPackMethod = function() {
9404  return this._getOption('horizontal') ? 'rowPack' : 'columnPack';
9405};
9406
9407
9408/**
9409 * set max X and Y value, for size of container
9410 * @param {Packery.Rect} rect
9411 * @private
9412 */
9413proto._setMaxXY = function( rect ) {
9414  this.maxX = Math.max( rect.x + rect.width, this.maxX );
9415  this.maxY = Math.max( rect.y + rect.height, this.maxY );
9416};
9417
9418/**
9419 * set the width and height of a rect, applying columnWidth and rowHeight
9420 * @param {Element} elem
9421 * @param {Packery.Rect} rect
9422 */
9423proto._setRectSize = function( elem, rect ) {
9424  var size = getSize( elem );
9425  var w = size.outerWidth;
9426  var h = size.outerHeight;
9427  // size for columnWidth and rowHeight, if available
9428  // only check if size is non-zero, #177
9429  if ( w || h ) {
9430    w = this._applyGridGutter( w, this.columnWidth );
9431    h = this._applyGridGutter( h, this.rowHeight );
9432  }
9433  // rect must fit in packer
9434  rect.width = Math.min( w, this.packer.width );
9435  rect.height = Math.min( h, this.packer.height );
9436};
9437
9438/**
9439 * fits item to columnWidth/rowHeight and adds gutter
9440 * @param {Number} measurement - item width or height
9441 * @param {Number} gridSize - columnWidth or rowHeight
9442 * @returns measurement
9443 */
9444proto._applyGridGutter = function( measurement, gridSize ) {
9445  // just add gutter if no gridSize
9446  if ( !gridSize ) {
9447    return measurement + this.gutter;
9448  }
9449  gridSize += this.gutter;
9450  // fit item to columnWidth/rowHeight
9451  var remainder = measurement % gridSize;
9452  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
9453  measurement = Math[ mathMethod ]( measurement / gridSize ) * gridSize;
9454  return measurement;
9455};
9456
9457proto._getContainerSize = function() {
9458  if ( this._getOption('horizontal') ) {
9459    return {
9460      width: this.maxX - this.gutter
9461    };
9462  } else {
9463    return {
9464      height: this.maxY - this.gutter
9465    };
9466  }
9467};
9468
9469
9470// -------------------------- stamp -------------------------- //
9471
9472/**
9473 * makes space for element
9474 * @param {Element} elem
9475 */
9476proto._manageStamp = function( elem ) {
9477
9478  var item = this.getItem( elem );
9479  var rect;
9480  if ( item && item.isPlacing ) {
9481    rect = item.rect;
9482  } else {
9483    var offset = this._getElementOffset( elem );
9484    rect = new Rect({
9485      x: this._getOption('originLeft') ? offset.left : offset.right,
9486      y: this._getOption('originTop') ? offset.top : offset.bottom
9487    });
9488  }
9489
9490  this._setRectSize( elem, rect );
9491  // save its space in the packer
9492  this.packer.placed( rect );
9493  this._setMaxXY( rect );
9494};
9495
9496// -------------------------- methods -------------------------- //
9497
9498function verticalSorter( a, b ) {
9499  return a.position.y - b.position.y || a.position.x - b.position.x;
9500}
9501
9502function horizontalSorter( a, b ) {
9503  return a.position.x - b.position.x || a.position.y - b.position.y;
9504}
9505
9506proto.sortItemsByPosition = function() {
9507  var sorter = this._getOption('horizontal') ? horizontalSorter : verticalSorter;
9508  this.items.sort( sorter );
9509};
9510
9511/**
9512 * Fit item element in its current position
9513 * Packery will position elements around it
9514 * useful for expanding elements
9515 *
9516 * @param {Element} elem
9517 * @param {Number} x - horizontal destination position, optional
9518 * @param {Number} y - vertical destination position, optional
9519 */
9520proto.fit = function( elem, x, y ) {
9521  var item = this.getItem( elem );
9522  if ( !item ) {
9523    return;
9524  }
9525
9526  // stamp item to get it out of layout
9527  this.stamp( item.element );
9528  // set placing flag
9529  item.enablePlacing();
9530  this.updateShiftTargets( item );
9531  // fall back to current position for fitting
9532  x = x === undefined ? item.rect.x: x;
9533  y = y === undefined ? item.rect.y: y;
9534  // position it best at its destination
9535  this.shift( item, x, y );
9536  this._bindFitEvents( item );
9537  item.moveTo( item.rect.x, item.rect.y );
9538  // layout everything else
9539  this.shiftLayout();
9540  // return back to regularly scheduled programming
9541  this.unstamp( item.element );
9542  this.sortItemsByPosition();
9543  item.disablePlacing();
9544};
9545
9546/**
9547 * emit event when item is fit and other items are laid out
9548 * @param {Packery.Item} item
9549 * @private
9550 */
9551proto._bindFitEvents = function( item ) {
9552  var _this = this;
9553  var ticks = 0;
9554  function onLayout() {
9555    ticks++;
9556    if ( ticks != 2 ) {
9557      return;
9558    }
9559    _this.dispatchEvent( 'fitComplete', null, [ item ] );
9560  }
9561  // when item is laid out
9562  item.once( 'layout', onLayout );
9563  // when all items are laid out
9564  this.once( 'layoutComplete', onLayout );
9565};
9566
9567// -------------------------- resize -------------------------- //
9568
9569// debounced, layout on resize
9570proto.resize = function() {
9571  // don't trigger if size did not change
9572  // or if resize was unbound. See #285, outlayer#9
9573  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
9574    return;
9575  }
9576
9577  if ( this.options.shiftPercentResize ) {
9578    this.resizeShiftPercentLayout();
9579  } else {
9580    this.layout();
9581  }
9582};
9583
9584/**
9585 * check if layout is needed post layout
9586 * @returns Boolean
9587 */
9588proto.needsResizeLayout = function() {
9589  var size = getSize( this.element );
9590  var innerSize = this._getOption('horizontal') ? 'innerHeight' : 'innerWidth';
9591  return size[ innerSize ] != this.size[ innerSize ];
9592};
9593
9594proto.resizeShiftPercentLayout = function() {
9595  var items = this._getItemsForLayout( this.items );
9596
9597  var isHorizontal = this._getOption('horizontal');
9598  var coord = isHorizontal ? 'y' : 'x';
9599  var measure = isHorizontal ? 'height' : 'width';
9600  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
9601  var innerSize = isHorizontal ? 'innerHeight' : 'innerWidth';
9602
9603  // proportional re-align items
9604  var previousSegment = this[ segmentName ];
9605  previousSegment = previousSegment && previousSegment + this.gutter;
9606
9607  if ( previousSegment ) {
9608    this._getMeasurements();
9609    var currentSegment = this[ segmentName ] + this.gutter;
9610    items.forEach( function( item ) {
9611      var seg = Math.round( item.rect[ coord ] / previousSegment );
9612      item.rect[ coord ] = seg * currentSegment;
9613    });
9614  } else {
9615    var currentSize = getSize( this.element )[ innerSize ] + this.gutter;
9616    var previousSize = this.packer[ measure ];
9617    items.forEach( function( item ) {
9618      item.rect[ coord ] = ( item.rect[ coord ] / previousSize ) * currentSize;
9619    });
9620  }
9621
9622  this.shiftLayout();
9623};
9624
9625// -------------------------- drag -------------------------- //
9626
9627/**
9628 * handle an item drag start event
9629 * @param {Element} elem
9630 */
9631proto.itemDragStart = function( elem ) {
9632  if ( !this.isEnabled ) {
9633    return;
9634  }
9635  this.stamp( elem );
9636  // this.ignore( elem );
9637  var item = this.getItem( elem );
9638  if ( !item ) {
9639    return;
9640  }
9641
9642  item.enablePlacing();
9643  item.showDropPlaceholder();
9644  this.dragItemCount++;
9645  this.updateShiftTargets( item );
9646};
9647
9648proto.updateShiftTargets = function( dropItem ) {
9649  this.shiftPacker.reset();
9650
9651  // pack stamps
9652  this._getBoundingRect();
9653  var isOriginLeft = this._getOption('originLeft');
9654  var isOriginTop = this._getOption('originTop');
9655  this.stamps.forEach( function( stamp ) {
9656    // ignore dragged item
9657    var item = this.getItem( stamp );
9658    if ( item && item.isPlacing ) {
9659      return;
9660    }
9661    var offset = this._getElementOffset( stamp );
9662    var rect = new Rect({
9663      x: isOriginLeft ? offset.left : offset.right,
9664      y: isOriginTop ? offset.top : offset.bottom
9665    });
9666    this._setRectSize( stamp, rect );
9667    // save its space in the packer
9668    this.shiftPacker.placed( rect );
9669  }, this );
9670
9671  // reset shiftTargets
9672  var isHorizontal = this._getOption('horizontal');
9673  var segmentName = isHorizontal ? 'rowHeight' : 'columnWidth';
9674  var measure = isHorizontal ? 'height' : 'width';
9675
9676  this.shiftTargetKeys = [];
9677  this.shiftTargets = [];
9678  var boundsSize;
9679  var segment = this[ segmentName ];
9680  segment = segment && segment + this.gutter;
9681
9682  if ( segment ) {
9683    var segmentSpan = Math.ceil( dropItem.rect[ measure ] / segment );
9684    var segs = Math.floor( ( this.shiftPacker[ measure ] + this.gutter ) / segment );
9685    boundsSize = ( segs - segmentSpan ) * segment;
9686    // add targets on top
9687    for ( var i=0; i < segs; i++ ) {
9688      this._addShiftTarget( i * segment, 0, boundsSize );
9689    }
9690  } else {
9691    boundsSize = ( this.shiftPacker[ measure ] + this.gutter ) - dropItem.rect[ measure ];
9692    this._addShiftTarget( 0, 0, boundsSize );
9693  }
9694
9695  // pack each item to measure where shiftTargets are
9696  var items = this._getItemsForLayout( this.items );
9697  var packMethod = this._getPackMethod();
9698  items.forEach( function( item ) {
9699    var rect = item.rect;
9700    this._setRectSize( item.element, rect );
9701    this.shiftPacker[ packMethod ]( rect );
9702
9703    // add top left corner
9704    this._addShiftTarget( rect.x, rect.y, boundsSize );
9705    // add bottom left / top right corner
9706    var cornerX = isHorizontal ? rect.x + rect.width : rect.x;
9707    var cornerY = isHorizontal ? rect.y : rect.y + rect.height;
9708    this._addShiftTarget( cornerX, cornerY, boundsSize );
9709
9710    if ( segment ) {
9711      // add targets for each column on bottom / row on right
9712      var segSpan = Math.round( rect[ measure ] / segment );
9713      for ( var i=1; i < segSpan; i++ ) {
9714        var segX = isHorizontal ? cornerX : rect.x + segment * i;
9715        var segY = isHorizontal ? rect.y + segment * i : cornerY;
9716        this._addShiftTarget( segX, segY, boundsSize );
9717      }
9718    }
9719  }, this );
9720
9721};
9722
9723proto._addShiftTarget = function( x, y, boundsSize ) {
9724  var checkCoord = this._getOption('horizontal') ? y : x;
9725  if ( checkCoord !== 0 && checkCoord > boundsSize ) {
9726    return;
9727  }
9728  // create string for a key, easier to keep track of what targets
9729  var key = x + ',' + y;
9730  var hasKey = this.shiftTargetKeys.indexOf( key ) != -1;
9731  if ( hasKey ) {
9732    return;
9733  }
9734  this.shiftTargetKeys.push( key );
9735  this.shiftTargets.push({ x: x, y: y });
9736};
9737
9738// -------------------------- drop -------------------------- //
9739
9740proto.shift = function( item, x, y ) {
9741  var shiftPosition;
9742  var minDistance = Infinity;
9743  var position = { x: x, y: y };
9744  this.shiftTargets.forEach( function( target ) {
9745    var distance = getDistance( target, position );
9746    if ( distance < minDistance ) {
9747      shiftPosition = target;
9748      minDistance = distance;
9749    }
9750  });
9751  item.rect.x = shiftPosition.x;
9752  item.rect.y = shiftPosition.y;
9753};
9754
9755function getDistance( a, b ) {
9756  var dx = b.x - a.x;
9757  var dy = b.y - a.y;
9758  return Math.sqrt( dx * dx + dy * dy );
9759}
9760
9761// -------------------------- drag move -------------------------- //
9762
9763var DRAG_THROTTLE_TIME = 120;
9764
9765/**
9766 * handle an item drag move event
9767 * @param {Element} elem
9768 * @param {Number} x - horizontal change in position
9769 * @param {Number} y - vertical change in position
9770 */
9771proto.itemDragMove = function( elem, x, y ) {
9772  var item = this.isEnabled && this.getItem( elem );
9773  if ( !item ) {
9774    return;
9775  }
9776
9777  x -= this.size.paddingLeft;
9778  y -= this.size.paddingTop;
9779
9780  var _this = this;
9781  function onDrag() {
9782    _this.shift( item, x, y );
9783    item.positionDropPlaceholder();
9784    _this.layout();
9785  }
9786
9787  // throttle
9788  var now = new Date();
9789  if ( this._itemDragTime && now - this._itemDragTime < DRAG_THROTTLE_TIME ) {
9790    clearTimeout( this.dragTimeout );
9791    this.dragTimeout = setTimeout( onDrag, DRAG_THROTTLE_TIME );
9792  } else {
9793    onDrag();
9794    this._itemDragTime = now;
9795  }
9796};
9797
9798// -------------------------- drag end -------------------------- //
9799
9800/**
9801 * handle an item drag end event
9802 * @param {Element} elem
9803 */
9804proto.itemDragEnd = function( elem ) {
9805  var item = this.isEnabled && this.getItem( elem );
9806  if ( !item ) {
9807    return;
9808  }
9809
9810  clearTimeout( this.dragTimeout );
9811  item.element.classList.add('is-positioning-post-drag');
9812
9813  var completeCount = 0;
9814  var _this = this;
9815  function onDragEndLayoutComplete() {
9816    completeCount++;
9817    if ( completeCount != 2 ) {
9818      return;
9819    }
9820    // reset drag item
9821    item.element.classList.remove('is-positioning-post-drag');
9822    item.hideDropPlaceholder();
9823    _this.dispatchEvent( 'dragItemPositioned', null, [ item ] );
9824  }
9825
9826  item.once( 'layout', onDragEndLayoutComplete );
9827  this.once( 'layoutComplete', onDragEndLayoutComplete );
9828  item.moveTo( item.rect.x, item.rect.y );
9829  this.layout();
9830  this.dragItemCount = Math.max( 0, this.dragItemCount - 1 );
9831  this.sortItemsByPosition();
9832  item.disablePlacing();
9833  this.unstamp( item.element );
9834};
9835
9836/**
9837 * binds Draggabilly events
9838 * @param {Draggabilly} draggie
9839 */
9840proto.bindDraggabillyEvents = function( draggie ) {
9841  this._bindDraggabillyEvents( draggie, 'on' );
9842};
9843
9844proto.unbindDraggabillyEvents = function( draggie ) {
9845  this._bindDraggabillyEvents( draggie, 'off' );
9846};
9847
9848proto._bindDraggabillyEvents = function( draggie, method ) {
9849  var handlers = this.handleDraggabilly;
9850  draggie[ method ]( 'dragStart', handlers.dragStart );
9851  draggie[ method ]( 'dragMove', handlers.dragMove );
9852  draggie[ method ]( 'dragEnd', handlers.dragEnd );
9853};
9854
9855/**
9856 * binds jQuery UI Draggable events
9857 * @param {jQuery} $elems
9858 */
9859proto.bindUIDraggableEvents = function( $elems ) {
9860  this._bindUIDraggableEvents( $elems, 'on' );
9861};
9862
9863proto.unbindUIDraggableEvents = function( $elems ) {
9864  this._bindUIDraggableEvents( $elems, 'off' );
9865};
9866
9867proto._bindUIDraggableEvents = function( $elems, method ) {
9868  var handlers = this.handleUIDraggable;
9869  $elems
9870    [ method ]( 'dragstart', handlers.start )
9871    [ method ]( 'drag', handlers.drag )
9872    [ method ]( 'dragstop', handlers.stop );
9873};
9874
9875// ----- destroy ----- //
9876
9877var _destroy = proto.destroy;
9878proto.destroy = function() {
9879  _destroy.apply( this, arguments );
9880  // disable flag; prevent drag events from triggering. #72
9881  this.isEnabled = false;
9882};
9883
9884// -----  ----- //
9885
9886Packery.Rect = Rect;
9887Packery.Packer = Packer;
9888
9889return Packery;
9890
9891}));
9892
9893/*!
9894 * Packery layout mode v2.0.1
9895 * sub-classes Packery
9896 */
9897
9898/*jshint browser: true, strict: true, undef: true, unused: true */
9899
9900( function( window, factory ) {
9901
9902  // universal module definition
9903  if ( typeof define == 'function' && define.amd ) {
9904    // AMD
9905    define( [
9906        'isotope-layout/js/layout-mode',
9907        'packery/js/packery'
9908      ],
9909      factory );
9910  } else if ( typeof module == 'object' && module.exports ) {
9911    // CommonJS
9912    module.exports = factory(
9913      require('isotope-layout/js/layout-mode'),
9914      require('packery')
9915    );
9916  } else {
9917    // browser global
9918    factory(
9919      window.Isotope.LayoutMode,
9920      window.Packery
9921    );
9922  }
9923
9924}( window, function factor( LayoutMode, Packery ) {
9925
9926
9927  // create an Outlayer layout class
9928  var PackeryMode = LayoutMode.create('packery');
9929  var proto = PackeryMode.prototype;
9930
9931  var keepModeMethods = {
9932    _getElementOffset: true,
9933    _getMeasurement: true
9934  };
9935
9936  // inherit Packery prototype
9937  for ( var method in Packery.prototype ) {
9938    // do not inherit mode methods
9939    if ( !keepModeMethods[ method ] ) {
9940      proto[ method ] = Packery.prototype[ method ];
9941    }
9942  }
9943
9944  // set packer in _resetLayout
9945  var _resetLayout = proto._resetLayout;
9946  proto._resetLayout = function() {
9947    this.packer = this.packer || new Packery.Packer();
9948    this.shiftPacker = this.shiftPacker || new Packery.Packer();
9949    _resetLayout.apply( this, arguments );
9950  };
9951
9952  var _getItemLayoutPosition = proto._getItemLayoutPosition;
9953  proto._getItemLayoutPosition = function( item ) {
9954    // set packery rect
9955    item.rect = item.rect || new Packery.Rect();
9956    return _getItemLayoutPosition.call( this, item );
9957  };
9958
9959  // needsResizeLayout for vertical or horizontal
9960  var _needsResizeLayout = proto.needsResizeLayout;
9961  proto.needsResizeLayout = function() {
9962    if ( this._getOption('horizontal') ) {
9963      return this.needsVerticalResizeLayout();
9964    } else {
9965      return _needsResizeLayout.call( this );
9966    }
9967  };
9968
9969  // point to mode options for horizontal
9970  var _getOption = proto._getOption;
9971  proto._getOption = function( option ) {
9972    if ( option == 'horizontal' ) {
9973      return this.options.isHorizontal !== undefined ?
9974        this.options.isHorizontal : this.options.horizontal;
9975    }
9976    return _getOption.apply( this.isotope, arguments );
9977  };
9978
9979  return PackeryMode;
9980
9981}));
9982
9983/*!
9984 * cellsByRows layout mode for Isotope
9985 * v1.1.3
9986 * http://isotope.metafizzy.co/layout-modes/cellsbyrow.html
9987 */
9988
9989/*jshint browser: true, devel: false, strict: true, undef: true, unused: true */
9990
9991( function( window, factory ) {
9992  // universal module definition
9993  /* jshint strict: false */ /*globals define, module, require */
9994  if ( typeof define === 'function' && define.amd ) {
9995    // AMD
9996    define( [
9997        'isotope/js/layout-mode'
9998      ],
9999      factory );
10000  } else if ( typeof exports === 'object' ) {
10001    // CommonJS
10002    module.exports = factory(
10003      require('isotope-layout/js/layout-mode')
10004    );
10005  } else {
10006    // browser global
10007    factory(
10008      window.Isotope.LayoutMode
10009    );
10010  }
10011
10012}( window, function factory( LayoutMode ) {
10013  'use strict';
10014
10015  var CellsByRow = LayoutMode.create( 'cellsByRow' );
10016  var proto = CellsByRow.prototype;
10017
10018  proto._resetLayout = function() {
10019    // reset properties
10020    this.itemIndex = 0;
10021    // measurements
10022    this.getColumnWidth();
10023    this.getRowHeight();
10024    // set cols
10025    this.cols = Math.floor( this.isotope.size.innerWidth / this.columnWidth );
10026    this.cols = Math.max( this.cols, 1 );
10027  };
10028
10029  proto._getItemLayoutPosition = function( item ) {
10030    item.getSize();
10031    var col = this.itemIndex % this.cols;
10032    var row = Math.floor( this.itemIndex / this.cols );
10033    // center item within cell
10034    var x = ( col + 0.5 ) * this.columnWidth - item.size.outerWidth / 2;
10035    var y = ( row + 0.5 ) * this.rowHeight - item.size.outerHeight / 2;
10036    this.itemIndex++;
10037    return { x: x, y: y };
10038  };
10039
10040  proto._getContainerSize = function() {
10041    return {
10042      height: Math.ceil( this.itemIndex / this.cols ) * this.rowHeight
10043    };
10044  };
10045
10046  return CellsByRow;
10047
10048}));
10049/*global jQuery: true */
10050
10051/*!
10052   --------------------------------
10053   Infinite Scroll
10054   --------------------------------
10055   + https://github.com/paulirish/infinite-scroll
10056   + version 2.1.0
10057   + Copyright 2011/12 Paul Irish & Luke Shumard
10058   + Licensed under the MIT license
10059
10060   + Documentation: http://infinite-scroll.com/
10061*/
10062
10063// Uses AMD or browser globals to create a jQuery plugin.
10064(function (factory) {
10065    if (typeof define === 'function' && define.amd) {
10066        // AMD. Register as an anonymous module.
10067        define(['jquery'], factory);
10068    } else {
10069        // Browser globals
10070        factory(jQuery);
10071    }
10072}(function ($, undefined) {
10073    'use strict';
10074
10075    $.infinitescroll = function infscr(options, callback, element) {
10076        this.element = $(element);
10077
10078        // Flag the object in the event of a failed creation
10079        if (!this._create(options, callback)) {
10080            this.failed = true;
10081        }
10082    };
10083
10084    $.infinitescroll.defaults = {
10085        loading: {
10086            finished: undefined,
10087            finishedMsg: "<em>Congratulations, you've reached the end of the internet.</em>",
10088            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
10088MzExnbRvQ2Sy7vN0zvVtNfU2tLY3rPgLdnDvca4VQS/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
10088iqpQpZ4apwSwRtjqrB3muoF9BboaXKmshlqWqsWiGt2wphJkQbAU5hoCACH5BAUKABsALAcABADOAAsAAAX/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',
10089            msg: null,
10090            msgText: '<em>Loading the next set of posts...</em>',
10091            selector: null,
10092            speed: 'fast',
10093            start: undefined
10094        },
10095        state: {
10096            isDuringAjax: false,
10097            isInvalidPage: false,
10098            isDestroyed: false,
10099            isDone: false, // For when it goes all the way through the archive.
10100            isPaused: false,
10101            isBeyondMaxPage: false,
10102            currPage: 1
10103        },
10104        debug: false,
10105        behavior: undefined,
10106        binder: $(window), // used to cache the selector
10107        nextSelector: 'div.navigation a:first',
10108        navSelector: 'div.navigation',
10109        contentSelector: null, // rename to pageFragment
10110        extraScrollPx: 150,
10111        itemSelector: 'div.post',
10112        animate: false,
10113        pathParse: undefined,
10114        dataType: 'html',
10115        appendCallback: true,
10116        bufferPx: 40,
10117        errorCallback: function () { },
10118        infid: 0, //Instance ID
10119        pixelsFromNavToBottom: undefined,
10120        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
10121        prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted
10122        maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work)
10123    };
10124
10125    $.infinitescroll.prototype = {
10126
10127        /*
10128            ----------------------------
10129            Private methods
10130            ----------------------------
10131            */
10132
10133        // Bind or unbind from scroll
10134        _binding: function infscr_binding(binding) {
10135
10136            var instance = this,
10137            opts = instance.options;
10138
10139            opts.v = '2.0b2.120520';
10140
10141            // if behavior is defined and this function is extended, call that instead of default
10142            if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) {
10143                this['_binding_'+opts.behavior].call(this);
10144                return;
10145            }
10146
10147            if (binding !== 'bind' && binding !== 'unbind') {
10148                this._debug('Binding value  ' + binding + ' not valid');
10149                return false;
10150            }
10151
10152            if (binding === 'unbind') {
10153                (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid);
10154            } else {
10155                (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () {
10156                    instance.scroll();
10157                });
10158            }
10159
10160            this._debug('Binding', binding);
10161        },
10162
10163        // Fundamental aspects of the plugin are initialized
10164        _create: function infscr_create(options, callback) {
10165
10166            // Add custom options to defaults
10167            var opts = $.extend(true, {}, $.infinitescroll.defaults, options);
10168            this.options = opts;
10169            var $window = $(window);
10170            var instance = this;
10171
10172            // Validate selectors
10173            if (!instance._validate(options)) {
10174                return false;
10175            }
10176
10177            // Validate page fragment path
10178            var path = $(opts.nextSelector).attr('href');
10179            if (!path) {
10180                this._debug('Navigation selector not found');
10181                return false;
10182            }
10183
10184            // Set the path to be a relative URL from root.
10185            opts.path = opts.path || this._determinepath(path);
10186
10187            // contentSelector is 'page fragment' option for .load() / .ajax() calls
10188            opts.contentSelector = opts.contentSelector || this.element;
10189
10190            // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector
10191            opts.loading.selector = opts.loading.selector || opts.contentSelector;
10192
10193            // Define loading.msg
10194            opts.loading.msg = opts.loading.msg || $('<div id="infscr-loading"><img alt="Loading..." src="' + opts.loading.img + '" /><div>' + opts.loading.msgText + '</div></div>');
10195
10196            // Preload loading.img
10197            (new Image()).src = opts.loading.img;
10198
10199            // distance from nav links to bottom
10200            // computed as: height of the document + top offset of container - top offset of nav link
10201            if(opts.pixelsFromNavToBottom === undefined) {
10202                opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top;
10203                this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom);
10204            }
10205
10206            var self = this;
10207
10208            // determine loading.start actions
10209            opts.loading.start = opts.loading.start || function() {
10210                $(opts.navSelector).hide();
10211                opts.loading.msg
10212                .appendTo(opts.loading.selector)
10213                .show(opts.loading.speed, $.proxy(function() {
10214                    this.beginAjax(opts);
10215                }, self));
10216            };
10217
10218            // determine loading.finished actions
10219            opts.loading.finished = opts.loading.finished || function() {
10220                if (!opts.state.isBeyondMaxPage)
10221                    opts.loading.msg.fadeOut(opts.loading.speed);
10222            };
10223
10224            // callback loading
10225            opts.callback = function(instance, data, url) {
10226                if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) {
10227                    instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url);
10228                }
10229
10230                if (callback) {
10231                    callback.call($(opts.contentSelector)[0], data, opts, url);
10232                }
10233
10234                if (opts.prefill) {
10235                    $window.bind('resize.infinite-scroll', instance._prefill);
10236                }
10237            };
10238
10239            if (options.debug) {
10240                // Tell IE9 to use its built-in console
10241                if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') {
10242                    ['log','info','warn','error','assert','dir','clear','profile','profileEnd']
10243                        .forEach(function (method) {
10244                            console[method] = this.call(console[method], console);
10245                        }, Function.prototype.bind);
10246                }
10247            }
10248
10249            this._setup();
10250
10251            // Setups the prefill method for use
10252            if (opts.prefill) {
10253                this._prefill();
10254            }
10255
10256            // Return true to indicate successful creation
10257            return true;
10258        },
10259
10260        _prefill: function infscr_prefill() {
10261            var instance = this;
10262            var $window = $(window);
10263
10264            function needsPrefill() {
10265                return ( $(instance.options.contentSelector).height() <= $window.height() );
10266            }
10267
10268            this._prefill = function() {
10269                if (needsPrefill()) {
10270                    instance.scroll();
10271                }
10272
10273                $window.bind('resize.infinite-scroll', function() {
10274                    if (needsPrefill()) {
10275                        $window.unbind('resize.infinite-scroll');
10276                        instance.scroll();
10277                    }
10278                });
10279            };
10280
10281            // Call self after setting up the new function
10282            this._prefill();
10283        },
10284
10285        // Console log wrapper
10286        _debug: function infscr_debug() {
10287            if (true !== this.options.debug) {
10288                return;
10289            }
10290
10291            if (typeof console !== 'undefined' && typeof console.log === 'function') {
10292                // Modern browsers
10293                // Single argument, which is a string
10294                if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') {
10295                    console.log( (Array.prototype.slice.call(arguments)).toString() );
10296                } else {
10297                    console.log( Array.prototype.slice.call(arguments) );
10298                }
10299            } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') {
10300                // IE8
10301                Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments));
10302            }
10303        },
10304
10305        // find the number to increment in the path.
10306        _determinepath: function infscr_determinepath(path) {
10307
10308            var opts = this.options;
10309
10310            // if behavior is defined and this function is extended, call that instead of default
10311            if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) {
10312                return this['_determinepath_'+opts.behavior].call(this,path);
10313            }
10314
10315            if (!!opts.pathParse) {
10316
10317                this._debug('pathParse manual');
10318                return opts.pathParse(path, this.options.state.currPage+1);
10319
10320            } else if (path.match(/^(.*?)\b2\b(.*?$)/)) {
10321                path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
10322
10323                // if there is any 2 in the url at all.
10324            } else if (path.match(/^(.*?)2(.*?$)/)) {
10325
10326                // page= is used in django:
10327                // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127
10328                if (path.match(/^(.*?page=)2(\/.*|$)/)) {
10329                    path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1);
10330                    return path;
10331                }
10332
10333                path = path.match(/^(.*?)2(.*?$)/).slice(1);
10334
10335            } else {
10336
10337                // page= is used in drupal too but second page is page=1 not page=2:
10338                // thx Jerod Fritz, vladikoff
10339                if (path.match(/^(.*?page=)1(\/.*|$)/)) {
10340                    path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1);
10341                    return path;
10342                } else {
10343                    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.");
10344                    // Get rid of isInvalidPage to allow permalink to state
10345                    opts.state.isInvalidPage = true;  //prevent it from running on this page.
10346                }
10347            }
10348            this._debug('determinePath', path);
10349            return path;
10350
10351        },
10352
10353        // Custom error
10354        _error: function infscr_error(xhr) {
10355
10356            var opts = this.options;
10357
10358            // if behavior is defined and this function is extended, call that instead of default
10359            if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) {
10360                this['_error_'+opts.behavior].call(this,xhr);
10361                return;
10362            }
10363
10364            if (xhr !== 'destroy' && xhr !== 'end') {
10365                xhr = 'unknown';
10366            }
10367
10368            this._debug('Error', xhr);
10369
10370            if (xhr === 'end' || opts.state.isBeyondMaxPage) {
10371                this._showdonemsg();
10372            }
10373
10374            opts.state.isDone = true;
10375            opts.state.currPage = 1; // if you need to go back to this instance
10376            opts.state.isPaused = false;
10377            opts.state.isBeyondMaxPage = false;
10378            this._binding('unbind');
10379
10380        },
10381
10382        // Load Callback
10383        _loadcallback: function infscr_loadcallback(box, data, url) {
10384            var opts = this.options,
10385            callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK
10386            result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append',
10387            frag;
10388
10389            // if behavior is defined and this function is extended, call that instead of default
10390            if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) {
10391                this['_loadcallback_'+opts.behavior].call(this,box,data);
10392                return;
10393            }
10394
10395            switch (result) {
10396                case 'done':
10397                    this._showdonemsg();
10398                    return false;
10399
10400                case 'no-append':
10401                    if (opts.dataType === 'html') {
10402                        data = '<div>' + data + '</div>';
10403                        data = $(data).find(opts.itemSelector);
10404                    }
10405
10406                    // if it didn't return anything
10407                    if (data.length === 0) {
10408                        return this._error('end');
10409                    }
10410
10411                    break;
10412
10413                case 'append':
10414                    var children = box.children();
10415                    // if it didn't return anything
10416                    if (children.length === 0) {
10417                        return this._error('end');
10418                    }
10419
10420                    // use a documentFragment because it works when content is going into a table or UL
10421                    frag = document.createDocumentFragment();
10422                    while (box[0].firstChild) {
10423                        frag.appendChild(box[0].firstChild);
10424                    }
10425
10426                    this._debug('contentSelector', $(opts.contentSelector)[0]);
10427                    $(opts.contentSelector)[0].appendChild(frag);
10428                    // previously, we would pass in the new DOM element as context for the callback
10429                    // however we're now using a documentfragment, which doesn't have parents or children,
10430                    // so the context is the contentContainer guy, and we pass in an array
10431                    // of the elements collected as the first argument.
10432
10433                    data = children.get();
10434                    break;
10435            }
10436
10437            // loadingEnd function
10438            opts.loading.finished.call($(opts.contentSelector)[0],opts);
10439
10440            // smooth scroll to ease in the new content
10441            if (opts.animate) {
10442                var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px';
10443                $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; });
10444            }
10445
10446            if (!opts.animate) {
10447                // once the call is done, we can allow it again.
10448                opts.state.isDuringAjax = false;
10449            }
10450
10451            callback(this, data, url);
10452
10453            if (opts.prefill) {
10454                this._prefill();
10455            }
10456        },
10457
10458        _nearbottom: function infscr_nearbottom() {
10459
10460            var opts = this.options,
10461            pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height();
10462
10463            // if behavior is defined and this function is extended, call that instead of default
10464            if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) {
10465                return this['_nearbottom_'+opts.behavior].call(this);
10466            }
10467
10468            this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom);
10469
10470            // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
10471            return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom);
10472
10473        },
10474
10475        // Pause / temporarily disable plugin from firing
10476        _pausing: function infscr_pausing(pause) {
10477
10478            var opts = this.options;
10479
10480            // if behavior is defined and this function is extended, call that instead of default
10481            if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) {
10482                this['_pausing_'+opts.behavior].call(this,pause);
10483                return;
10484            }
10485
10486            // If pause is not 'pause' or 'resume', toggle it's value
10487            if (pause !== 'pause' && pause !== 'resume' && pause !== null) {
10488                this._debug('Invalid argument. Toggling pause value instead');
10489            }
10490
10491            pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle';
10492
10493            switch (pause) {
10494                case 'pause':
10495                    opts.state.isPaused = true;
10496                break;
10497
10498                case 'resume':
10499                    opts.state.isPaused = false;
10500                break;
10501
10502                case 'toggle':
10503                    opts.state.isPaused = !opts.state.isPaused;
10504                break;
10505            }
10506
10507            this._debug('Paused', opts.state.isPaused);
10508            return false;
10509
10510        },
10511
10512        // Behavior is determined
10513        // If the behavior option is undefined, it will set to default and bind to scroll
10514        _setup: function infscr_setup() {
10515
10516            var opts = this.options;
10517
10518            // if behavior is defined and this function is extended, call that instead of default
10519            if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) {
10520                this['_setup_'+opts.behavior].call(this);
10521                return;
10522            }
10523
10524            this._binding('bind');
10525
10526            return false;
10527
10528        },
10529
10530        // Show done message
10531        _showdonemsg: function infscr_showdonemsg() {
10532
10533            var opts = this.options;
10534
10535            // if behavior is defined and this function is extended, call that instead of default
10536            if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) {
10537                this['_showdonemsg_'+opts.behavior].call(this);
10538                return;
10539            }
10540
10541            opts.loading.msg
10542            .find('img')
10543            .hide()
10544            .parent()
10545            .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () {
10546                $(this).parent().fadeOut(opts.loading.speed);
10547            });
10548
10549            // user provided callback when done
10550            opts.errorCallback.call($(opts.contentSelector)[0],'done');
10551        },
10552
10553        // grab each selector option and see if any fail
10554        _validate: function infscr_validate(opts) {
10555            for (var key in opts) {
10556                if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) {
10557                    this._debug('Your ' + key + ' found no elements.');
10558                    return false;
10559                }
10560            }
10561
10562            return true;
10563        },
10564
10565        /*
10566            ----------------------------
10567            Public methods
10568            ----------------------------
10569            */
10570
10571        // Bind to scroll
10572        bind: function infscr_bind() {
10573            this._binding('bind');
10574        },
10575
10576        // Destroy current instance of plugin
10577        destroy: function infscr_destroy() {
10578            this.options.state.isDestroyed = true;
10579            this.options.loading.finished();
10580            return this._error('destroy');
10581        },
10582
10583        // Set pause value to false
10584        pause: function infscr_pause() {
10585            this._pausing('pause');
10586        },
10587
10588        // Set pause value to false
10589        resume: function infscr_resume() {
10590            this._pausing('resume');
10591        },
10592
10593        beginAjax: function infscr_ajax(opts) {
10594            var instance = this,
10595                path = opts.path,
10596                box, desturl, method, condition;
10597
10598            // increment the URL bit. e.g. /page/3/
10599            opts.state.currPage++;
10600
10601            // Manually control maximum page
10602            if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){
10603                opts.state.isBeyondMaxPage = true;
10604                this.destroy();
10605                return;
10606            }
10607
10608            // if we're dealing with a table we can't use DIVs
10609            box = $(opts.contentSelector).is('table, tbody') ? $('<tbody/>') : $('<div/>');
10610
10611            desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage);
10612            instance._debug('heading into ajax', desturl);
10613
10614            method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback';
10615            if (opts.appendCallback && opts.dataType === 'html') {
10616                method += '+callback';
10617            }
10618
10619            switch (method) {
10620                case 'html+callback':
10621                    instance._debug('Using HTML via .load() method');
10622                    box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) {
10623                        instance._loadcallback(box, responseText, desturl);
10624                    });
10625
10626                    break;
10627
10628                case 'html':
10629                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
10630                    $.ajax({
10631                        // params
10632                        url: desturl,
10633                        dataType: opts.dataType,
10634                        complete: function infscr_ajax_callback(jqXHR, textStatus) {
10635                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
10636                            if (condition) {
10637                                instance._loadcallback(box, jqXHR.responseText, desturl);
10638                            } else {
10639                                instance._error('end');
10640                            }
10641                        }
10642                    });
10643
10644                    break;
10645                case 'json':
10646                    instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method');
10647                    $.ajax({
10648                        dataType: 'json',
10649                        type: 'GET',
10650                        url: desturl,
10651                        success: function (data, textStatus, jqXHR) {
10652                            condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified');
10653                            if (opts.appendCallback) {
10654                                // if appendCallback is true, you must defined template in options.
10655                                // note that data passed into _loadcallback is already an html (after processed in opts.template(data)).
10656                                if (opts.template !== undefined) {
10657                                    var theData = opts.template(data);
10658                                    box.append(theData);
10659                                    if (condition) {
10660                                        instance._loadcallback(box, theData);
10661                                    } else {
10662                                        instance._error('end');
10663                                    }
10664                                } else {
10665                                    instance._debug('template must be defined.');
10666                                    instance._error('end');
10667                                }
10668                            } else {
10669                                // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback.
10670                                if (condition) {
10671                                    instance._loadcallback(box, data, desturl);
10672                                } else {
10673                                    instance._error('end');
10674                                }
10675                            }
10676                        },
10677                        error: function() {
10678                            instance._debug('JSON ajax request failed.');
10679                            instance._error('end');
10680                        }
10681                    });
10682
10683                    break;
10684            }
10685        },
10686
10687        // Retrieve next set of content items
10688        retrieve: function infscr_retrieve(pageNum) {
10689            pageNum = pageNum || null;
10690
10691            var instance = this,
10692            opts = instance.options;
10693
10694            // if behavior is defined and this function is extended, call that instead of default
10695            if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) {
10696                this['retrieve_'+opts.behavior].call(this,pageNum);
10697                return;
10698            }
10699
10700            // for manual triggers, if destroyed, get out of here
10701            if (opts.state.isDestroyed) {
10702                this._debug('Instance is destroyed');
10703                return false;
10704            }
10705
10706            // we dont want to fire the ajax multiple times
10707            opts.state.isDuringAjax = true;
10708
10709            opts.loading.start.call($(opts.contentSelector)[0],opts);
10710        },
10711
10712        // Check to see next page is needed
10713        scroll: function infscr_scroll() {
10714
10715            var opts = this.options,
10716            state = opts.state;
10717
10718            // if behavior is defined and this function is extended, call that instead of default
10719            if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) {
10720                this['scroll_'+opts.behavior].call(this);
10721                return;
10722            }
10723
10724            if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) {
10725                return;
10726            }
10727
10728            if (!this._nearbottom()) {
10729                return;
10730            }
10731
10732            this.retrieve();
10733
10734        },
10735
10736        // Toggle pause value
10737        toggle: function infscr_toggle() {
10738            this._pausing();
10739        },
10740
10741        // Unbind from scroll
10742        unbind: function infscr_unbind() {
10743            this._binding('unbind');
10744        },
10745
10746        // update options
10747        update: function infscr_options(key) {
10748            if ($.isPlainObject(key)) {
10749                this.options = $.extend(true,this.options,key);
10750            }
10751        }
10752    };
10753
10754
10755    /*
10756        ----------------------------
10757        Infinite Scroll function
10758        ----------------------------
10759
10760        Borrowed logic from the following...
10761
10762        jQuery UI
10763        - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
10764
10765        jCarousel
10766        - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
10767
10768        Masonry
10769        - https://github.com/desandro/masonry/blob/master/jquery.masonry.js
10770
10771*/
10772
10773    $.fn.infinitescroll = function infscr_init(options, callback) {
10774
10775
10776        var thisCall = typeof options;
10777
10778        switch (thisCall) {
10779
10780            // method
10781            case 'string':
10782                var args = Array.prototype.slice.call(arguments, 1);
10783
10784                this.each(function () {
10785                    var instance = $.data(this, 'infinitescroll');
10786
10787                    if (!instance) {
10788                        // not setup yet
10789                        // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup');
10790                        return false;
10791                    }
10792
10793                    if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
10794                        // return $.error('No such method ' + options + ' for Infinite Scroll');
10795                        return false;
10796                    }
10797
10798                    // no errors!
10799                    instance[options].apply(instance, args);
10800                });
10801
10802            break;
10803
10804            // creation
10805            case 'object':
10806
10807                this.each(function () {
10808
10809                var instance = $.data(this, 'infinitescroll');
10810
10811                if (instance) {
10812
10813                    // update options of current instance
10814                    instance.update(options);
10815
10816                } else {
10817
10818                    // initialize new instance
10819                    instance = new $.infinitescroll(options, callback, this);
10820
10821                    // don't attach if instantiation failed
10822                    if (!instance.failed) {
10823                        $.data(this, 'infinitescroll', instance);
10824                    }
10825
10826                }
10827
10828            });
10829
10830            break;
10831
10832        }
10833
10834        return this;
10835    };
10836
10837
10838
10839    /*
10840     * smartscroll: debounced scroll event for jQuery *
10841     * https://github.com/lukeshumard/smartscroll
10842     * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js *
10843     * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. *
10844     */
10845
10846    var event = $.event,
10847    scrollTimeout;
10848
10849    event.special.smartscroll = {
10850        setup: function () {
10851            $(this).bind('scroll', event.special.smartscroll.handler);
10852        },
10853        teardown: function () {
10854            $(this).unbind('scroll', event.special.smartscroll.handler);
10855        },
10856        handler: function (event, execAsap) {
10857            // Save the context
10858            var context = this,
10859            args = arguments;
10860
10861            // set correct event type
10862            event.type = 'smartscroll';
10863
10864            if (scrollTimeout) { clearTimeout(scrollTimeout); }
10865            scrollTimeout = setTimeout(function () {
10866                $(context).trigger('smartscroll', args);
10867            }, execAsap === 'execAsap' ? 0 : 100);
10868        }
10869    };
10870
10871    $.fn.smartscroll = function (fn) {
10872        return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']);
10873    };
10874
10875}));
10876
10877/*!
10878Waypoints - 4.0.1
10879Copyright © 2011-2016 Caleb Troughton
10880Licensed under the MIT license.
10881https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
10882*/
10883(function() {
10884  'use strict'
10885
10886  var keyCounter = 0
10887  var allWaypoints = {}
10888
10889  /* http://imakewebthings.com/waypoints/api/waypoint */
10890  function Waypoint(options) {
10891    if (!options) {
10892      throw new Error('No options passed to Waypoint constructor')
10893    }
10894    if (!options.element) {
10895      throw new Error('No element option passed to Waypoint constructor')
10896    }
10897    if (!options.handler) {
10898      throw new Error('No handler option passed to Waypoint constructor')
10899    }
10900
10901    this.key = 'waypoint-' + keyCounter
10902    this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
10903    this.element = this.options.element
10904    this.adapter = new Waypoint.Adapter(this.element)
10905    this.callback = options.handler
10906    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
10907    this.enabled = this.options.enabled
10908    this.triggerPoint = null
10909    this.group = Waypoint.Group.findOrCreate({
10910      name: this.options.group,
10911      axis: this.axis
10912    })
10913    this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
10914
10915    if (Waypoint.offsetAliases[this.options.offset]) {
10916      this.options.offset = Waypoint.offsetAliases[this.options.offset]
10917    }
10918    this.group.add(this)
10919    this.context.add(this)
10920    allWaypoints[this.key] = this
10921    keyCounter += 1
10922  }
10923
10924  /* Private */
10925  Waypoint.prototype.queueTrigger = function(direction) {
10926    this.group.queueTrigger(this, direction)
10927  }
10928
10929  /* Private */
10930  Waypoint.prototype.trigger = function(args) {
10931    if (!this.enabled) {
10932      return
10933    }
10934    if (this.callback) {
10935      this.callback.apply(this, args)
10936    }
10937  }
10938
10939  /* Public */
10940  /* http://imakewebthings.com/waypoints/api/destroy */
10941  Waypoint.prototype.destroy = function() {
10942    this.context.remove(this)
10943    this.group.remove(this)
10944    delete allWaypoints[this.key]
10945  }
10946
10947  /* Public */
10948  /* http://imakewebthings.com/waypoints/api/disable */
10949  Waypoint.prototype.disable = function() {
10950    this.enabled = false
10951    return this
10952  }
10953
10954  /* Public */
10955  /* http://imakewebthings.com/waypoints/api/enable */
10956  Waypoint.prototype.enable = function() {
10957    this.context.refresh()
10958    this.enabled = true
10959    return this
10960  }
10961
10962  /* Public */
10963  /* http://imakewebthings.com/waypoints/api/next */
10964  Waypoint.prototype.next = function() {
10965    return this.group.next(this)
10966  }
10967
10968  /* Public */
10969  /* http://imakewebthings.com/waypoints/api/previous */
10970  Waypoint.prototype.previous = function() {
10971    return this.group.previous(this)
10972  }
10973
10974  /* Private */
10975  Waypoint.invokeAll = function(method) {
10976    var allWaypointsArray = []
10977    for (var waypointKey in allWaypoints) {
10978      allWaypointsArray.push(allWaypoints[waypointKey])
10979    }
10980    for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
10981      allWaypointsArray[i][method]()
10982    }
10983  }
10984
10985  /* Public */
10986  /* http://imakewebthings.com/waypoints/api/destroy-all */
10987  Waypoint.destroyAll = function() {
10988    Waypoint.invokeAll('destroy')
10989  }
10990
10991  /* Public */
10992  /* http://imakewebthings.com/waypoints/api/disable-all */
10993  Waypoint.disableAll = function() {
10994    Waypoint.invokeAll('disable')
10995  }
10996
10997  /* Public */
10998  /* http://imakewebthings.com/waypoints/api/enable-all */
10999  Waypoint.enableAll = function() {
11000    Waypoint.Context.refreshAll()
11001    for (var waypointKey in allWaypoints) {
11002      allWaypoints[waypointKey].enabled = true
11003    }
11004    return this
11005  }
11006
11007  /* Public */
11008  /* http://imakewebthings.com/waypoints/api/refresh-all */
11009  Waypoint.refreshAll = function() {
11010    Waypoint.Context.refreshAll()
11011  }
11012
11013  /* Public */
11014  /* http://imakewebthings.com/waypoints/api/viewport-height */
11015  Waypoint.viewportHeight = function() {
11016    return window.innerHeight || document.documentElement.clientHeight
11017  }
11018
11019  /* Public */
11020  /* http://imakewebthings.com/waypoints/api/viewport-width */
11021  Waypoint.viewportWidth = function() {
11022    return document.documentElement.clientWidth
11023  }
11024
11025  Waypoint.adapters = []
11026
11027  Waypoint.defaults = {
11028    context: window,
11029    continuous: true,
11030    enabled: true,
11031    group: 'default',
11032    horizontal: false,
11033    offset: 0
11034  }
11035
11036  Waypoint.offsetAliases = {
11037    'bottom-in-view': function() {
11038      return this.context.innerHeight() - this.adapter.outerHeight()
11039    },
11040    'right-in-view': function() {
11041      return this.context.innerWidth() - this.adapter.outerWidth()
11042    }
11043  }
11044
11045  window.Waypoint = Waypoint
11046}())
11047;(function() {
11048  'use strict'
11049
11050  function requestAnimationFrameShim(callback) {
11051    window.setTimeout(callback, 1000 / 60)
11052  }
11053
11054  var keyCounter = 0
11055  var contexts = {}
11056  var Waypoint = window.Waypoint
11057  var oldWindowLoad = window.onload
11058
11059  /* http://imakewebthings.com/waypoints/api/context */
11060  function Context(element) {
11061    this.element = element
11062    this.Adapter = Waypoint.Adapter
11063    this.adapter = new this.Adapter(element)
11064    this.key = 'waypoint-context-' + keyCounter
11065    this.didScroll = false
11066    this.didResize = false
11067    this.oldScroll = {
11068      x: this.adapter.scrollLeft(),
11069      y: this.adapter.scrollTop()
11070    }
11071    this.waypoints = {
11072      vertical: {},
11073      horizontal: {}
11074    }
11075
11076    element.waypointContextKey = this.key
11077    contexts[element.waypointContextKey] = this
11078    keyCounter += 1
11079    if (!Waypoint.windowContext) {
11080      Waypoint.windowContext = true
11081      Waypoint.windowContext = new Context(window)
11082    }
11083
11084    this.createThrottledScrollHandler()
11085    this.createThrottledResizeHandler()
11086  }
11087
11088  /* Private */
11089  Context.prototype.add = function(waypoint) {
11090    var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
11091    this.waypoints[axis][waypoint.key] = waypoint
11092    this.refresh()
11093  }
11094
11095  /* Private */
11096  Context.prototype.checkEmpty = function() {
11097    var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
11098    var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
11099    var isWindow = this.element == this.element.window
11100    if (horizontalEmpty && verticalEmpty && !isWindow) {
11101      this.adapter.off('.waypoints')
11102      delete contexts[this.key]
11103    }
11104  }
11105
11106  /* Private */
11107  Context.prototype.createThrottledResizeHandler = function() {
11108    var self = this
11109
11110    function resizeHandler() {
11111      self.handleResize()
11112      self.didResize = false
11113    }
11114
11115    this.adapter.on('resize.waypoints', function() {
11116      if (!self.didResize) {
11117        self.didResize = true
11118        Waypoint.requestAnimationFrame(resizeHandler)
11119      }
11120    })
11121  }
11122
11123  /* Private */
11124  Context.prototype.createThrottledScrollHandler = function() {
11125    var self = this
11126    function scrollHandler() {
11127      self.handleScroll()
11128      self.didScroll = false
11129    }
11130
11131    this.adapter.on('scroll.waypoints', function() {
11132      if (!self.didScroll || Waypoint.isTouch) {
11133        self.didScroll = true
11134        Waypoint.requestAnimationFrame(scrollHandler)
11135      }
11136    })
11137  }
11138
11139  /* Private */
11140  Context.prototype.handleResize = function() {
11141    Waypoint.Context.refreshAll()
11142  }
11143
11144  /* Private */
11145  Context.prototype.handleScroll = function() {
11146    var triggeredGroups = {}
11147    var axes = {
11148      horizontal: {
11149        newScroll: this.adapter.scrollLeft(),
11150        oldScroll: this.oldScroll.x,
11151        forward: 'right',
11152        backward: 'left'
11153      },
11154      vertical: {
11155        newScroll: this.adapter.scrollTop(),
11156        oldScroll: this.oldScroll.y,
11157        forward: 'down',
11158        backward: 'up'
11159      }
11160    }
11161
11162    for (var axisKey in axes) {
11163      var axis = axes[axisKey]
11164      var isForward = axis.newScroll > axis.oldScroll
11165      var direction = isForward ? axis.forward : axis.backward
11166
11167      for (var waypointKey in this.waypoints[axisKey]) {
11168        var waypoint = this.waypoints[axisKey][waypointKey]
11169        if (waypoint.triggerPoint === null) {
11170          continue
11171        }
11172        var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
11173        var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
11174        var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
11175        var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
11176        if (crossedForward || crossedBackward) {
11177          waypoint.queueTrigger(direction)
11178          triggeredGroups[waypoint.group.id] = waypoint.group
11179        }
11180      }
11181    }
11182
11183    for (var groupKey in triggeredGroups) {
11184      triggeredGroups[groupKey].flushTriggers()
11185    }
11186
11187    this.oldScroll = {
11188      x: axes.horizontal.newScroll,
11189      y: axes.vertical.newScroll
11190    }
11191  }
11192
11193  /* Private */
11194  Context.prototype.innerHeight = function() {
11195    /*eslint-disable eqeqeq */
11196    if (this.element == this.element.window) {
11197      return Waypoint.viewportHeight()
11198    }
11199    /*eslint-enable eqeqeq */
11200    return this.adapter.innerHeight()
11201  }
11202
11203  /* Private */
11204  Context.prototype.remove = function(waypoint) {
11205    delete this.waypoints[waypoint.axis][waypoint.key]
11206    this.checkEmpty()
11207  }
11208
11209  /* Private */
11210  Context.prototype.innerWidth = function() {
11211    /*eslint-disable eqeqeq */
11212    if (this.element == this.element.window) {
11213      return Waypoint.viewportWidth()
11214    }
11215    /*eslint-enable eqeqeq */
11216    return this.adapter.innerWidth()
11217  }
11218
11219  /* Public */
11220  /* http://imakewebthings.com/waypoints/api/context-destroy */
11221  Context.prototype.destroy = function() {
11222    var allWaypoints = []
11223    for (var axis in this.waypoints) {
11224      for (var waypointKey in this.waypoints[axis]) {
11225        allWaypoints.push(this.waypoints[axis][waypointKey])
11226      }
11227    }
11228    for (var i = 0, end = allWaypoints.length; i < end; i++) {
11229      allWaypoints[i].destroy()
11230    }
11231  }
11232
11233  /* Public */
11234  /* http://imakewebthings.com/waypoints/api/context-refresh */
11235  Context.prototype.refresh = function() {
11236    /*eslint-disable eqeqeq */
11237    var isWindow = this.element == this.element.window
11238    /*eslint-enable eqeqeq */
11239    var contextOffset = isWindow ? undefined : this.adapter.offset()
11240    var triggeredGroups = {}
11241    var axes
11242
11243    this.handleScroll()
11244    axes = {
11245      horizontal: {
11246        contextOffset: isWindow ? 0 : contextOffset.left,
11247        contextScroll: isWindow ? 0 : this.oldScroll.x,
11248        contextDimension: this.innerWidth(),
11249        oldScroll: this.oldScroll.x,
11250        forward: 'right',
11251        backward: 'left',
11252        offsetProp: 'left'
11253      },
11254      vertical: {
11255        contextOffset: isWindow ? 0 : contextOffset.top,
11256        contextScroll: isWindow ? 0 : this.oldScroll.y,
11257        contextDimension: this.innerHeight(),
11258        oldScroll: this.oldScroll.y,
11259        forward: 'down',
11260        backward: 'up',
11261        offsetProp: 'top'
11262      }
11263    }
11264
11265    for (var axisKey in axes) {
11266      var axis = axes[axisKey]
11267      for (var waypointKey in this.waypoints[axisKey]) {
11268        var waypoint = this.waypoints[axisKey][waypointKey]
11269        var adjustment = waypoint.options.offset
11270        var oldTriggerPoint = waypoint.triggerPoint
11271        var elementOffset = 0
11272        var freshWaypoint = oldTriggerPoint == null
11273        var contextModifier, wasBeforeScroll, nowAfterScroll
11274        var triggeredBackward, triggeredForward
11275
11276        if (waypoint.element !== waypoint.element.window) {
11277          elementOffset = waypoint.adapter.offset()[axis.offsetProp]
11278        }
11279
11280        if (typeof adjustment === 'function') {
11281          adjustment = adjustment.apply(waypoint)
11282        }
11283        else if (typeof adjustment === 'string') {
11284          adjustment = parseFloat(adjustment)
11285          if (waypoint.options.offset.indexOf('%') > - 1) {
11286            adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
11287          }
11288        }
11289
11290        contextModifier = axis.contextScroll - axis.contextOffset
11291        waypoint.triggerPoint = Math.floor(elementOffset + contextModifier - adjustment)
11292        wasBeforeScroll = oldTriggerPoint < axis.oldScroll
11293        nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
11294        triggeredBackward = wasBeforeScroll && nowAfterScroll
11295        triggeredForward = !wasBeforeScroll && !nowAfterScroll
11296
11297        if (!freshWaypoint && triggeredBackward) {
11298          waypoint.queueTrigger(axis.backward)
11299          triggeredGroups[waypoint.group.id] = waypoint.group
11300        }
11301        else if (!freshWaypoint && triggeredForward) {
11302          waypoint.queueTrigger(axis.forward)
11303          triggeredGroups[waypoint.group.id] = waypoint.group
11304        }
11305        else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
11306          waypoint.queueTrigger(axis.forward)
11307          triggeredGroups[waypoint.group.id] = waypoint.group
11308        }
11309      }
11310    }
11311
11312    Waypoint.requestAnimationFrame(function() {
11313      for (var groupKey in triggeredGroups) {
11314        triggeredGroups[groupKey].flushTriggers()
11315      }
11316    })
11317
11318    return this
11319  }
11320
11321  /* Private */
11322  Context.findOrCreateByElement = function(element) {
11323    return Context.findByElement(element) || new Context(element)
11324  }
11325
11326  /* Private */
11327  Context.refreshAll = function() {
11328    for (var contextId in contexts) {
11329      contexts[contextId].refresh()
11330    }
11331  }
11332
11333  /* Public */
11334  /* http://imakewebthings.com/waypoints/api/context-find-by-element */
11335  Context.findByElement = function(element) {
11336    return contexts[element.waypointContextKey]
11337  }
11338
11339  window.onload = function() {
11340    if (oldWindowLoad) {
11341      oldWindowLoad()
11342    }
11343    Context.refreshAll()
11344  }
11345
11346
11347  Waypoint.requestAnimationFrame = function(callback) {
11348    var requestFn = window.requestAnimationFrame ||
11349      window.mozRequestAnimationFrame ||
11350      window.webkitRequestAnimationFrame ||
11351      requestAnimationFrameShim
11352    requestFn.call(window, callback)
11353  }
11354  Waypoint.Context = Context
11355}())
11356;(function() {
11357  'use strict'
11358
11359  function byTriggerPoint(a, b) {
11360    return a.triggerPoint - b.triggerPoint
11361  }
11362
11363  function byReverseTriggerPoint(a, b) {
11364    return b.triggerPoint - a.triggerPoint
11365  }
11366
11367  var groups = {
11368    vertical: {},
11369    horizontal: {}
11370  }
11371  var Waypoint = window.Waypoint
11372
11373  /* http://imakewebthings.com/waypoints/api/group */
11374  function Group(options) {
11375    this.name = options.name
11376    this.axis = options.axis
11377    this.id = this.name + '-' + this.axis
11378    this.waypoints = []
11379    this.clearTriggerQueues()
11380    groups[this.axis][this.name] = this
11381  }
11382
11383  /* Private */
11384  Group.prototype.add = function(waypoint) {
11385    this.waypoints.push(waypoint)
11386  }
11387
11388  /* Private */
11389  Group.prototype.clearTriggerQueues = function() {
11390    this.triggerQueues = {
11391      up: [],
11392      down: [],
11393      left: [],
11394      right: []
11395    }
11396  }
11397
11398  /* Private */
11399  Group.prototype.flushTriggers = function() {
11400    for (var direction in this.triggerQueues) {
11401      var waypoints = this.triggerQueues[direction]
11402      var reverse = direction === 'up' || direction === 'left'
11403      waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
11404      for (var i = 0, end = waypoints.length; i < end; i += 1) {
11405        var waypoint = waypoints[i]
11406        if (waypoint.options.continuous || i === waypoints.length - 1) {
11407          waypoint.trigger([direction])
11408        }
11409      }
11410    }
11411    this.clearTriggerQueues()
11412  }
11413
11414  /* Private */
11415  Group.prototype.next = function(waypoint) {
11416    this.waypoints.sort(byTriggerPoint)
11417    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
11418    var isLast = index === this.waypoints.length - 1
11419    return isLast ? null : this.waypoints[index + 1]
11420  }
11421
11422  /* Private */
11423  Group.prototype.previous = function(waypoint) {
11424    this.waypoints.sort(byTriggerPoint)
11425    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
11426    return index ? this.waypoints[index - 1] : null
11427  }
11428
11429  /* Private */
11430  Group.prototype.queueTrigger = function(waypoint, direction) {
11431    this.triggerQueues[direction].push(waypoint)
11432  }
11433
11434  /* Private */
11435  Group.prototype.remove = function(waypoint) {
11436    var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
11437    if (index > -1) {
11438      this.waypoints.splice(index, 1)
11439    }
11440  }
11441
11442  /* Public */
11443  /* http://imakewebthings.com/waypoints/api/first */
11444  Group.prototype.first = function() {
11445    return this.waypoints[0]
11446  }
11447
11448  /* Public */
11449  /* http://imakewebthings.com/waypoints/api/last */
11450  Group.prototype.last = function() {
11451    return this.waypoints[this.waypoints.length - 1]
11452  }
11453
11454  /* Private */
11455  Group.findOrCreate = function(options) {
11456    return groups[options.axis][options.name] || new Group(options)
11457  }
11458
11459  Waypoint.Group = Group
11460}())
11461;(function() {
11462  'use strict'
11463
11464  var $ = window.jQuery
11465  var Waypoint = window.Waypoint
11466
11467  function JQueryAdapter(element) {
11468    this.$element = $(element)
11469  }
11470
11471  $.each([
11472    'innerHeight',
11473    'innerWidth',
11474    'off',
11475    'offset',
11476    'on',
11477    'outerHeight',
11478    'outerWidth',
11479    'scrollLeft',
11480    'scrollTop'
11481  ], function(i, method) {
11482    JQueryAdapter.prototype[method] = function() {
11483      var args = Array.prototype.slice.call(arguments)
11484      return this.$element[method].apply(this.$element, args)
11485    }
11486  })
11487
11488  $.each([
11489    'extend',
11490    'inArray',
11491    'isEmptyObject'
11492  ], function(i, method) {
11493    JQueryAdapter[method] = $[method]
11494  })
11495
11496  Waypoint.adapters.push({
11497    name: 'jquery',
11498    Adapter: JQueryAdapter
11499  })
11500  Waypoint.Adapter = JQueryAdapter
11501}())
11502;(function() {
11503  'use strict'
11504
11505  var Waypoint = window.Waypoint
11506
11507  function createExtension(framework) {
11508    return function() {
11509      var waypoints = []
11510      var overrides = arguments[0]
11511
11512      if (framework.isFunction(arguments[0])) {
11513        overrides = framework.extend({}, arguments[1])
11514        overrides.handler = arguments[0]
11515      }
11516
11517      this.each(function() {
11518        var options = framework.extend({}, overrides, {
11519          element: this
11520        })
11521        if (typeof options.context === 'string') {
11522          options.context = framework(this).closest(options.context)[0]
11523        }
11524        waypoints.push(new Waypoint(options))
11525      })
11526
11527      return waypoints
11528    }
11529  }
11530
11531  if (window.jQuery) {
11532    window.jQuery.fn.waypoint = createExtension(window.jQuery)
11533  }
11534  if (window.Zepto) {
11535    window.Zepto.fn.waypoint = createExtension(window.Zepto)
11536  }
11537}())
11538;
11539/*!
11540Waypoints Inview Shortcut - 4.0.1
11541Copyright © 2011-2016 Caleb Troughton
11542Licensed under the MIT license.
11543https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
11544*/
11545(function() {
11546  'use strict'
11547
11548  function noop() {}
11549
11550  var Waypoint = window.Waypoint
11551
11552  /* http://imakewebthings.com/waypoints/shortcuts/inview */
11553  function Inview(options) {
11554    this.options = Waypoint.Adapter.extend({}, Inview.defaults, options)
11555    this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
11556    this.waypoints = []
11557    this.element = this.options.element
11558    this.createWaypoints()
11559  }
11560
11561  /* Private */
11562  Inview.prototype.createWaypoints = function() {
11563    var configs = {
11564      vertical: [{
11565        down: 'enter',
11566        up: 'exited',
11567        offset: '100%'
11568      }, {
11569        down: 'entered',
11570        up: 'exit',
11571        offset: 'bottom-in-view'
11572      }, {
11573        down: 'exit',
11574        up: 'entered',
11575        offset: 0
11576      }, {
11577        down: 'exited',
11578        up: 'enter',
11579        offset: function() {
11580          return -this.adapter.outerHeight()
11581        }
11582      }],
11583      horizontal: [{
11584        right: 'enter',
11585        left: 'exited',
11586        offset: '100%'
11587      }, {
11588        right: 'entered',
11589        left: 'exit',
11590        offset: 'right-in-view'
11591      }, {
11592        right: 'exit',
11593        left: 'entered',
11594        offset: 0
11595      }, {
11596        right: 'exited',
11597        left: 'enter',
11598        offset: function() {
11599          return -this.adapter.outerWidth()
11600        }
11601      }]
11602    }
11603
11604    for (var i = 0, end = configs[this.axis].length; i < end; i++) {
11605      var config = configs[this.axis][i]
11606      this.createWaypoint(config)
11607    }
11608  }
11609
11610  /* Private */
11611  Inview.prototype.createWaypoint = function(config) {
11612    var self = this
11613    this.waypoints.push(new Waypoint({
11614      context: this.options.context,
11615      element: this.options.element,
11616      enabled: this.options.enabled,
11617      handler: (function(config) {
11618        return function(direction) {
11619          self.options[config[direction]].call(self, direction)
11620        }
11621      }(config)),
11622      offset: config.offset,
11623      horizontal: this.options.horizontal
11624    }))
11625  }
11626
11627  /* Public */
11628  Inview.prototype.destroy = function() {
11629    for (var i = 0, end = this.waypoints.length; i < end; i++) {
11630      this.waypoints[i].destroy()
11631    }
11632    this.waypoints = []
11633  }
11634
11635  Inview.prototype.disable = function() {
11636    for (var i = 0, end = this.waypoints.length; i < end; i++) {
11637      this.waypoints[i].disable()
11638    }
11639  }
11640
11641  Inview.prototype.enable = function() {
11642    for (var i = 0, end = this.waypoints.length; i < end; i++) {
11643      this.waypoints[i].enable()
11644    }
11645  }
11646
11647  Inview.defaults = {
11648    context: window,
11649    enabled: true,
11650    enter: noop,
11651    entered: noop,
11652    exit: noop,
11653    exited: noop
11654  }
11655
11656  Waypoint.Inview = Inview
11657}())
11658;
11659
11660/*
11661 * SmartMenus jQuery v0.9.6
11662 * http://www.smartmenus.org/
11663 *
11664 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd.
11665 * http://vadikom.com/
11666 *
11667 * Released under the MIT license:
11668 * http://www.opensource.org/licenses/MIT
11669 */
11670
11671(function($) {
11672
11673	var menuTrees = [],
11674		IE = !!window.createPopup, // we need to detect it, unfortunately
11675		IElt9 = IE && !document.defaultView,
11676		IElt8 = IE && !document.querySelector,
11677		IE6 = IE && typeof document.documentElement.currentStyle.minWidth == 'undefined',
11678		mouse = false, // optimize for touch by default - we will detect for mouse input
11679		mouseDetectionEnabled = false;
11680
11681	// Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.)
11682	function initMouseDetection(disable) {
11683		if (!mouseDetectionEnabled && !disable) {
11684			// if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present
11685			// 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)
11686			var firstTime = true,
11687				lastMove = null;
11688			$(document).bind({
11689				'mousemove.smartmenus_mouse': function(e) {
11690					var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() };
11691					if (lastMove) {
11692						var deltaX = Math.abs(lastMove.x - thisMove.x),
11693							deltaY = Math.abs(lastMove.y - thisMove.y);
11694	 					if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) {
11695							mouse = true;
11696							// 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
11697							if (firstTime) {
11698								var $a = $(e.target).closest('a');
11699								if ($a.is('a')) {
11700									$.each(menuTrees, function() {
11701										if ($.contains(this.$root[0], $a[0])) {
11702											this.itemEnter({ currentTarget: $a[0] });
11703											return false;
11704										}
11705									});
11706								}
11707								firstTime = false;
11708							}
11709						}
11710					}
11711					lastMove = thisMove;
11712				},
11713				'touchstart.smartmenus_mouse pointerover.smartmenus_mouse MSPointerOver.smartmenus_mouse': function(e) {
11714					if (!/^(4|mouse)$/.test(e.originalEvent.pointerType)) {
11715						mouse = false;
11716					}
11717				}
11718			});
11719			mouseDetectionEnabled = true;
11720		} else if (mouseDetectionEnabled && disable) {
11721			$(document).unbind('.smartmenus_mouse');
11722			mouseDetectionEnabled = false;
11723		}
11724	};
11725
11726	$.SmartMenus = function(elm, options) {
11727		this.$root = $(elm);
11728		this.opts = options;
11729		this.rootId = ''; // internal
11730		this.$subArrow = null;
11731		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)
11732		this.activatedItems = []; // stores last activated A's for each level
11733		this.visibleSubMenus = []; // stores visible sub menus UL's
11734		this.showTimeout = 0;
11735		this.hideTimeout = 0;
11736		this.scrollTimeout = 0;
11737		this.clickActivated = false;
11738		this.zIndexInc = 0;
11739		this.$firstLink = null; // we'll use these for some tests
11740		this.$firstSub = null; // at runtime so we'll cache them
11741		this.disabled = false;
11742		this.$disableOverlay = null;
11743		this.init();
11744	};
11745
11746	$.extend($.SmartMenus, {
11747		hideAll: function() {
11748			$.each(menuTrees, function() {
11749				this.menuHideAll();
11750			});
11751		},
11752		destroy: function() {
11753			while (menuTrees.length) {
11754				menuTrees[0].destroy();
11755			}
11756			initMouseDetection(true);
11757		},
11758		prototype: {
11759			init: function(refresh) {
11760				var self = this;
11761
11762				if (!refresh) {
11763					menuTrees.push(this);
11764
11765					this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, '');
11766
11767					if (this.$root.hasClass('sm-rtl')) {
11768						this.opts.rightToLeftSubMenus = true;
11769					}
11770
11771					// init root (main menu)
11772					this.$root
11773						.data('smartmenus', this)
11774						.attr('data-smartmenus-id', this.rootId)
11775						.dataSM('level', 1)
11776						.bind({
11777							'mouseover.smartmenus focusin.smartmenus': $.proxy(this.rootOver, this),
11778							'mouseout.smartmenus focusout.smartmenus': $.proxy(this.rootOut, this)
11779						})
11780						.delegate('a, div.logo-container', {
11781							'mouseenter.smartmenus': $.proxy(this.itemEnter, this),
11782							'mouseleave.smartmenus': $.proxy(this.itemLeave, this),
11783							'mousedown.smartmenus': $.proxy(this.itemDown, this),
11784							'focus.smartmenus': $.proxy(this.itemFocus, this),
11785							'blur.smartmenus': $.proxy(this.itemBlur, this),
11786							'click.smartmenus': $.proxy(this.itemClick, this),
11787							'touchend.smartmenus': $.proxy(this.itemTouchEnd, this)
11788						});
11789
11790					var eNamespace = '.smartmenus' + this.rootId;
11791					// hide menus on tap or click outside the root UL
11792					if (this.opts.hideOnClick) {
11793						$(document).bind('touchstart' + eNamespace, $.proxy(this.docTouchStart, this))
11794							.bind('touchmove' + eNamespace, $.proxy(this.docTouchMove, this))
11795							.bind('touchend' + eNamespace, $.proxy(this.docTouchEnd, this))
11796							// for Opera Mobile < 11.5, webOS browser, etc. we'll check click too
11797							.bind('click' + eNamespace, $.proxy(this.docClick, this));
11798					}
11799					// hide sub menus on resize
11800					$(window).bind('resize' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
11801					$(window).bind('scroll' + eNamespace + ' orientationchange' + eNamespace, $.proxy(this.winResize, this));
11802
11803					if (this.opts.subIndicators) {
11804						this.$subArrow = $('<span/>').addClass('sub-arrow');
11805						if (this.opts.subIndicatorsText) {
11806							this.$subArrow.html(this.opts.subIndicatorsText);
11807						}
11808					}
11809
11810					// make sure mouse detection is enabled
11811					initMouseDetection();
11812				}
11813
11814				// init sub menus
11815				this.$firstSub = this.$root.find('ul').each(function() { self.menuInit($(this)); }).eq(0);
11816
11817				this.$firstLink = this.$root.find('a').eq(0);
11818
11819				// find current item
11820				if (this.opts.markCurrentItem) {
11821					var reDefaultDoc = /(index|default)\.[^#\?\/]*/i,
11822						reHash = /#.*/,
11823						locHref = window.location.href.replace(reDefaultDoc, ''),
11824						locHrefNoHash = locHref.replace(reHash, '');
11825					this.$root.find('a').each(function() {
11826						var href = this.href.replace(reDefaultDoc, ''),
11827							$this = $(this);
11828						if (href == locHref || href == locHrefNoHash) {
11829							$this.addClass('current');
11830							if (self.opts.markCurrentTree) {
11831								$this.parents('li').each(function() {
11832									var $this = $(this);
11833									if ($this.dataSM('sub')) {
11834										$this.children('a').addClass('current');
11835									}
11836								});
11837							}
11838						}
11839					});
11840				}
11841			},
11842			destroy: function() {
11843				this.menuHideAll();
11844				this.$root
11845					.removeData('smartmenus')
11846					.removeAttr('data-smartmenus-id')
11847					.removeDataSM('level')
11848					.unbind('.smartmenus')
11849					.undelegate('.smartmenus');
11850				var eNamespace = '.smartmenus' + this.rootId;
11851				$(document).unbind(eNamespace);
11852				$(window).unbind(eNamespace);
11853				if (this.opts.subIndicators) {
11854					this.$subArrow = null;
11855				}
11856				var self = this;
11857				$.each(this.subMenus, function() {
11858					if (this.hasClass('mega-menu')) {
11859						this.find('ul').removeDataSM('in-mega');
11860					}
11861					if (this.dataSM('shown-before')) {
11862						if (IElt8) {
11863							this.children().css({ styleFloat: '', width: '' });
11864						}
11865						if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) {
11866							if (!IE6) {
11867								this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap');
11868							} else {
11869								this.css({ width: '', overflowX: '', overflowY: '' }).children().children('a').css('white-space', '');
11870							}
11871						}
11872						if (this.dataSM('scroll-arrows')) {
11873							this.dataSM('scroll-arrows').remove();
11874						}
11875						this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' });
11876					}
11877					if (self.opts.subIndicators) {
11878						this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove();
11879					}
11880					this.removeDataSM('shown-before')
11881						.removeDataSM('ie-shim')
11882						.removeDataSM('scroll-arrows')
11883						.removeDataSM('parent-a')
11884						.removeDataSM('level')
11885						.removeDataSM('beforefirstshowfired')
11886						.parent().removeDataSM('sub');
11887				});
11888				if (this.opts.markCurrentItem) {
11889					this.$root.find('a.current').removeClass('current');
11890				}
11891				this.$root = null;
11892				this.$firstLink = null;
11893				this.$firstSub = null;
11894				if (this.$disableOverlay) {
11895					this.$disableOverlay.remove();
11896					this.$disableOverlay = null;
11897				}
11898				menuTrees.splice($.inArray(this, menuTrees), 1);
11899			},
11900			disable: function(noOverlay) {
11901				if (!this.disabled) {
11902					this.menuHideAll();
11903					// display overlay over the menu to prevent interaction
11904					if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) {
11905						var pos = this.$root.offset();
11906						this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({
11907							position: 'absolute',
11908							top: pos.top,
11909							left: pos.left,
11910							width: this.$root.outerWidth(),
11911							height: this.$root.outerHeight(),
11912							zIndex: this.getStartZIndex() + 1,
11913							opacity: 0
11914						}).appendTo(document.body);
11915					}
11916					this.disabled = true;
11917				}
11918			},
11919			docClick: function(e) {
11920				// hide on any click outside the menu or on a menu link
11921				if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) {
11922					this.menuHideAll($(e.target));
11923				}
11924			},
11925			docTouchEnd: function(e) {
11926				if (!this.lastTouch) {
11927					return;
11928				}
11929				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))) {
11930					if (this.hideTimeout) {
11931						clearTimeout(this.hideTimeout);
11932						this.hideTimeout = 0;
11933					}
11934					// hide with a delay to prevent triggering accidental unwanted click on some page element
11935					var self = this;
11936					this.hideTimeout = setTimeout(function() { self.menuHideAll($(e.target)); }, 350);
11937				}
11938				this.lastTouch = null;
11939			},
11940			docTouchMove: function(e) {
11941				if (!this.lastTouch) {
11942					return;
11943				}
11944				var touchPoint = e.originalEvent.touches[0];
11945				this.lastTouch.x2 = touchPoint.pageX;
11946				this.lastTouch.y2 = touchPoint.pageY;
11947			},
11948			docTouchStart: function(e) {
11949				var touchPoint = e.originalEvent.touches[0];
11950				this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target };
11951			},
11952			enable: function() {
11953				if (this.disabled) {
11954					if (this.$disableOverlay) {
11955						this.$disableOverlay.remove();
11956						this.$disableOverlay = null;
11957					}
11958					this.disabled = false;
11959				}
11960			},
11961			getHeight: function($elm) {
11962				return this.getOffset($elm, true);
11963			},
11964			// returns precise width/height float values in IE9+, FF4+, recent WebKit
11965			// http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
11966			getOffset: function($elm, height) {
11967				var old;
11968				if ($elm.css('display') == 'none') {
11969					old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility };
11970					$elm.css({ position: 'absolute', visibility: 'hidden' }).show();
11971				}
11972				var defaultView = $elm[0].ownerDocument.defaultView,
11973					compStyle = defaultView && defaultView.getComputedStyle && defaultView.getComputedStyle($elm[0], null),
11974					val = compStyle && parseFloat(compStyle[height ? 'height' : 'width']);
11975				if (val) {
11976					val += parseFloat(compStyle[height ? 'paddingTop' : 'paddingLeft'])
11977	 					+ parseFloat(compStyle[height ? 'paddingBottom' : 'paddingRight'])
11978	 					+ parseInt(compStyle[height ? 'borderTopWidth' : 'borderLeftWidth'])
11979	 					+ parseInt(compStyle[height ? 'borderBottomWidth' : 'borderRightWidth']);
11980				} else {
11981					val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth;
11982				}
11983				if (old) {
11984					$elm.hide().css(old);
11985				}
11986				return val;
11987			},
11988			getWidth: function($elm) {
11989				return this.getOffset($elm);
11990			},
11991			getStartZIndex: function() {
11992				var zIndex = parseInt(this.$root.css('z-index'));
11993				return !isNaN(zIndex) ? zIndex : 1;
11994			},
11995			handleEvents: function() {
11996				return !this.disabled && this.isCSSOn();
11997			},
11998			handleItemEvents: function($a) {
11999				return this.handleEvents() && !this.isLinkInMegaMenu($a);
12000			},
12001			isCollapsible: function() {
12002				return this.$firstSub.css('position') == 'static';
12003			},
12004			isCSSOn: function() {
12005				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';
12006			},
12007			isFixed: function() {
12008				return this.$root.css('position') == 'fixed';
12009			},
12010			isLinkInMegaMenu: function($a) {
12011				return !$a.parent().parent().dataSM('level');
12012			},
12013			isTouchMode: function() {
12014				return !mouse || this.isCollapsible();
12015			},
12016			itemActivate: function($a) {
12017				var $li = $a.parent(),
12018					$ul = $li.parent(),
12019					level = $ul.dataSM('level');
12020				// 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
12021				if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) {
12022					var self = this;
12023					$($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function() {
12024						self.itemActivate($(this).dataSM('parent-a'));
12025					});
12026				}
12027				// hide any visible deeper level sub menus
12028				if (this.visibleSubMenus.length > level) {
12029					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--) {
12030						this.menuHide(this.visibleSubMenus[i]);
12031					}
12032				}
12033				// save new active item and sub menu for this level
12034				this.activatedItems[level - 1] = $a;
12035				this.visibleSubMenus[level - 1] = $ul;
12036				if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) {
12037					return;
12038				}
12039				// show the sub menu if this item has one
12040				var $sub = $li.dataSM('sub');
12041				if ($sub && (this.isTouchMode() || (!this.opts.showOnClick || this.clickActivated))) {
12042					this.menuShow($sub);
12043				}
12044			},
12045			itemBlur: function(e) {
12046				var $a = $(e.currentTarget);
12047				if (!this.handleItemEvents($a)) {
12048					return;
12049				}
12050				this.$root.triggerHandler('blur.smapi', $a[0]);
12051			},
12052			itemClick: function(e) {
12053				var $a = $(e.currentTarget);
12054
12055				if (!this.handleItemEvents($a)) {
12056					return;
12057				}
12058				$a.removeDataSM('mousedown');
12059				if (this.$root.triggerHandler('click.smapi', $a[0]) === false) {
12060					return false;
12061				}
12062				var $sub = $a.parent().dataSM('sub');
12063				if (this.isTouchMode()) {
12064					// undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu
12065					if ($a.dataSM('href')) {
12066						$a.attr('href', $a.dataSM('href')).removeDataSM('href');
12067					}
12068					// if the sub is not visible
12069					if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
12070						// try to activate the item and show the sub
12071						this.itemActivate($a);
12072						// if "itemActivate" showed the sub, prevent the click so that the link is not loaded
12073						// 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
12074						if ($sub.is(':visible')) {
12075							return false;
12076						}
12077					}
12078				} else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) {
12079					this.clickActivated = true;
12080					this.menuShow($sub);
12081					return false;
12082				}
12083				if ($a.hasClass('disabled')) {
12084					return false;
12085				}
12086				if (this.$root.triggerHandler('select.smapi', $a[0]) === false) {
12087					return false;
12088				}
12089			},
12090			itemDown: function(e) {
12091				var $a = $(e.currentTarget);
12092				if (!this.handleItemEvents($a)) {
12093					return;
12094				}
12095				$a.dataSM('mousedown', true);
12096			},
12097			itemEnter: function(e) {
12098				var $a = $(e.currentTarget);
12099				if (!this.handleItemEvents($a)) {
12100					return;
12101				}
12102				if (!this.isTouchMode()) {
12103					if (this.showTimeout) {
12104						clearTimeout(this.showTimeout);
12105						this.showTimeout = 0;
12106					}
12107					var self = this;
12108					this.showTimeout = setTimeout(function() { self.itemActivate($a); }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout);
12109				}
12110				this.$root.triggerHandler('mouseenter.smapi', $a[0]);
12111			},
12112			itemFocus: function(e) {
12113				var $a = $(e.currentTarget);
12114				if (!this.handleItemEvents($a)) {
12115					return;
12116				}
12117				// 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
12118				if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) {
12119					this.itemActivate($a);
12120				}
12121				this.$root.triggerHandler('focus.smapi', $a[0]);
12122			},
12123			itemLeave: function(e) {
12124				var $a = $(e.currentTarget);
12125				if (!this.handleItemEvents($a)) {
12126					return;
12127				}
12128				if (!this.isTouchMode()) {
12129					if ($a[0].blur) {
12130						$a[0].blur();
12131					}
12132					if (this.showTimeout) {
12133						clearTimeout(this.showTimeout);
12134						this.showTimeout = 0;
12135					}
12136				}
12137				$a.removeDataSM('mousedown');
12138				this.$root.triggerHandler('mouseleave.smapi', $a[0]);
12139			},
12140			itemTouchEnd: function(e) {
12141				var $a = $(e.currentTarget);
12142				if (!this.handleItemEvents($a)) {
12143					return;
12144				}
12145				// prevent the address bar on iPhone from sliding down when expanding a sub menu
12146				var $sub = $a.parent().dataSM('sub');
12147				if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) {
12148					$a.dataSM('href', $a.attr('href'));
12149					$a.attr('href', '#');
12150				}
12151			},
12152			menuFixLayout: function($ul) {
12153				// fixes a menu that is being shown for the first time
12154				if (!$ul.dataSM('shown-before')) {
12155					$ul.hide().dataSM('shown-before', true);
12156					// fix the layout of the items in IE<8
12157					if (IElt8) {
12158						$ul.children().css({ styleFloat: 'left', width: '100%' });
12159					}
12160				}
12161			},
12162			menuHide: function($sub) {
12163				if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) {
12164					return;
12165				}
12166				$sub.stop(true, true);
12167				if ($sub.is(':visible')) {
12168					var complete = function() {
12169						// unset z-index
12170						if (IElt9) {
12171							$sub.parent().css('z-index', '');
12172						} else {
12173							$sub.css('z-index', '');
12174						}
12175					};
12176					// if sub is collapsible (mobile view)
12177					if (this.isCollapsible()) {
12178						if (this.opts.collapsibleHideFunction) {
12179							this.opts.collapsibleHideFunction.call(this, $sub, complete);
12180						} else {
12181							$sub.hide(this.opts.collapsibleHideDuration, complete);
12182						}
12183					} else {
12184						if (this.opts.hideFunction) {
12185							this.opts.hideFunction.call(this, $sub, complete);
12186						} else {
12187							$sub.hide(this.opts.hideDuration, complete);
12188						}
12189					}
12190					// remove IE iframe shim
12191					if ($sub.dataSM('ie-shim')) {
12192						$sub.dataSM('ie-shim').remove();
12193					}
12194					// deactivate scrolling if it is activated for this sub
12195					if ($sub.dataSM('scroll')) {
12196						$sub.unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide();
12197					}
12198					// unhighlight parent item
12199					$sub.dataSM('parent-a').removeClass('highlighted');
12200					var level = $sub.dataSM('level');
12201					this.activatedItems.splice(level - 1, 1);
12202					this.visibleSubMenus.splice(level - 1, 1);
12203					this.$root.triggerHandler('hide.smapi', $sub[0]);
12204				}
12205			},
12206			menuHideAll: function($item) {
12207				if ($item != undefined && $item.parent().hasClass('menu-item') && !$item.parent().hasClass('menu-item-has-children')) return;
12208				var $win = $(window),
12209					winW = $win.width();
12210				if ( $('body').hasClass('vmenu') && winW >= 560 ) {
12211					return;
12212				}
12213				if (this.showTimeout) {
12214					clearTimeout(this.showTimeout);
12215					this.showTimeout = 0;
12216				}
12217				// hide all subs
12218				for (var i = this.visibleSubMenus.length - 1; i > 0; i--) {
12219					this.menuHide(this.visibleSubMenus[i]);
12220				}
12221				// hide root if it's popup
12222				if (this.opts.isPopup) {
12223					this.$root.stop(true, true);
12224					if (this.$root.is(':visible')) {
12225						if (this.opts.hideFunction) {
12226							this.opts.hideFunction.call(this, this.$root);
12227						} else {
12228							this.$root.hide(this.opts.hideDuration);
12229						}
12230						// remove IE iframe shim
12231						if (this.$root.dataSM('ie-shim')) {
12232							this.$root.dataSM('ie-shim').remove();
12233						}
12234					}
12235				}
12236				this.activatedItems = [];
12237				this.visibleSubMenus = [];
12238				this.clickActivated = false;
12239				// reset z-index increment
12240				this.zIndexInc = 0;
12241			},
12242			menuIframeShim: function($ul) {
12243				// create iframe shim for the menu
12244				if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) {
12245					$ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 })
12246						.css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })
12247					);
12248				}
12249			},
12250			menuInit: function($ul) {
12251				if (!$ul.dataSM('in-mega')) {
12252					this.subMenus.push($ul);
12253					// mark UL's in mega drop downs (if any) so we can neglect them
12254					if ($ul.hasClass('mega-menu')) {
12255						$ul.find('ul').dataSM('in-mega', true);
12256					}
12257					// get level (much faster than, for example, using parentsUntil)
12258					var level = 2,
12259						par = $ul[0];
12260					while (par != null && par.parentNode != null && ( par = par.parentNode.parentNode) != this.$root[0]) {
12261						level++;
12262					}
12263					// cache stuff
12264					$ul.dataSM('parent-a', $ul.prevAll('a').eq(-1))
12265						.dataSM('level', level)
12266						.parent().dataSM('sub', $ul);
12267					// add sub indicator to parent item
12268					if (this.opts.subIndicators) {
12269						$ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone());
12270					}
12271				}
12272			},
12273			menuPosition: function($sub) {
12274				var fixIE = $('html.ie').length;
12275				// if (fixIE) {
12276				// 	var $rowParent = $($sub).closest('.main-menu-container');
12277				// 	$rowParent.height($rowParent.height());
12278				// }
12279				var $a = $sub.dataSM('parent-a'),
12280					$li = $sub.parent(),
12281					$ul = $sub.parent().parent(),
12282					// $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'),
12283					$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'),
12284					level = $sub.dataSM('level'),
12285					subW = this.getWidth($sub),
12286					subH = this.getHeight($sub),
12287					itemOffset = $a.offset(),
12288					itemX = itemOffset.left,
12289					itemY = itemOffset.top,
12290					itemW = this.getWidth($a),
12291					itemH = this.getHeight($a),
12292					$win = $(window),
12293					winX = $win.scrollLeft(),
12294					winY = $win.scrollTop(),
12295					winW = $win.width(),
12296					winH = $win.height(),
12297					containerW = $container.width(),
12298					containerOffsetX = containerW + ((winW - containerW) / 2),
12299					horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'),
12300					subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX,
12301					subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY,
12302					x, y, leftPos;
12303
12304				if (horizontalParent) {
12305					x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX;
12306					y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY;
12307				} else {
12308					x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : subW - subOffsetX;
12309					y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY;
12310				}
12311				if (this.opts.keepInViewport && !this.isCollapsible()) {
12312					if (this.isFixed()) {
12313						itemX -= winX;
12314						itemY -= winY;
12315						winX = winY = 0;
12316					}
12317					var absX = itemX + x,
12318						absY = itemY + y;
12319					if (this.opts.rightToLeftSubMenus && absX < winX) {
12320						x = horizontalParent ? winX - absX + x : itemW - subOffsetX;
12321					} else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + containerOffsetX ) {
12322						x = horizontalParent ? winX + containerOffsetX - subW - absX + x : subOffsetX - subW;
12323					}
12324					if (!horizontalParent) {
12325						if (subH < winH && absY + subH > winY + winH) {
12326							y += winY + winH - subH - absY;
12327						} else if (subH >= winH || absY < winY) {
12328							y += winY - absY;
12329						}
12330					}
12331					// do we need scrolling?
12332					// 0.49 added for the sake of IE9/FF4+ where we might be dealing with float numbers for "subH"
12333					if (mouse && (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49)) {
12334						var self = this;
12335						if (!$sub.dataSM('scroll-arrows')) {
12336							$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]])
12337								.bind({
12338									mouseenter: function() { self.menuScroll($sub, $(this).hasClass('scroll-up')); },
12339									mouseleave: function(e) {
12340										self.menuScrollStop($sub);
12341										self.menuScrollOut($sub, e);
12342									},
12343									'mousewheel DOMMouseScroll': function(e) { e.preventDefault(); }
12344								})
12345								.insertAfter($sub)
12346							);
12347						}
12348						// bind events to show/hide arrows on hover and save scrolling data for this sub
12349						var vportY = winY - (itemY + itemH);
12350						$sub.dataSM('scroll', {
12351								vportY: vportY,
12352								subH: subH,
12353								winH: winH,
12354								step: 1
12355							})
12356							.bind({
12357								'mouseover.smartmenus_scroll': function(e) { self.menuScrollOver($sub, e); },
12358								'mouseout.smartmenus_scroll': function(e) { self.menuScrollOut($sub, e); },
12359								'mousewheel.smartmenus_scroll DOMMouseScroll.smartmenus_scroll': function(e) { self.menuScrollMousewheel($sub, e); }
12360							})
12361							.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
12361StartZIndex() + this.zIndexInc })
12362							.eq(0).css('margin-top', vportY).end()
12363							.eq(1).css('margin-top', vportY + winH - this.getHeight($sub.dataSM('scroll-arrows').eq(1))).end()
12364							.eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show();
12365					}
12366				}
12367				if ( !$sub.closest('.menu-accordion').length ) {
12368					var rightPos = 'auto';
12369					if ( $sub.parents('.isotope-filters').length ) {
12370						if ( $sub.parents('.text-right').eq(0).length ) {
12371							leftPos = '0px';
12372							rightPos = 'auto';
12373						} else {
12374							leftPos = 'auto';
12375							rightPos = '0px';
12376						}
12377						x = 0;
12378					} else {
12379						if ( $sub.hasClass('mega-menu-inner') ) {
12380							$sub.css({ width: containerW});
12381							leftPos = -1 * (parseFloat($sub.closest('ul.menu-smart').offset().left) - parseFloat($sub.closest('.row-menu').offset().left));
12382							if ( ! $('body').hasClass('megamenu-side-to-side') ) {
12383								leftPos += parseFloat($sub.closest('.row-menu-inner').css('paddingLeft'));
12384							}
12385							x = 0;
12386						} else {
12387							leftPos = (level > 2 ? $li.position().left - parseFloat($li.closest('ul').css('paddingLeft')) : $li.position().left ) + 'px';
12388							x = (level > 2 && x >= 0) ? x + 1 : x - 1;
12389						}
12390					}
12391				}
12392
12393				// $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) });
12394				$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) });
12395				// IE iframe shim
12396				this.menuIframeShim($sub);
12397				if ($sub.dataSM('ie-shim')) {
12398					$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) });
12399				}
12400			},
12401			menuScroll: function($sub, up, wheel) {
12402				var y = parseFloat($sub.css('margin-top')),
12403					scroll = $sub.dataSM('scroll'),
12404					end = scroll.vportY + (up ? 0 : scroll.winH - scroll.subH),
12405					step = wheel || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor($sub.dataSM('scroll').step);
12406				$sub.add($sub.dataSM('ie-shim')).css('margin-top', Math.abs(end - y) > step ? y + (up ? step : -step) : end);
12407				y = parseFloat($sub.css('margin-top'));
12408				// show opposite arrow if appropriate
12409				if (up && y + scroll.subH > scroll.vportY + scroll.winH || !up && y < scroll.vportY) {
12410					$sub.dataSM('scroll-arrows').eq(up ? 1 : 0).show();
12411				}
12412				// accelerate when not using mousewheel to scroll
12413				if (!wheel && this.opts.scrollAccelerate && $sub.dataSM('scroll').step < this.opts.scrollStep) {
12414					$sub.dataSM('scroll').step += 0.5;
12415				}
12416				// "y" and "end" might be float numbers in IE9/FF4+ so this weird way to check is used
12417				if (Math.abs(y - end) < 1) {
12418					$sub.dataSM('scroll-arrows').eq(up ? 0 : 1).hide();
12419					$sub.dataSM('scroll').step = 1;
12420				} else if (!wheel) {
12421					var self = this;
12422					this.scrollTimeout = setTimeout(function() { self.menuScroll($sub, up); }, this.opts.scrollInterval);
12423				}
12424			},
12425			menuScrollMousewheel: function($sub, e) {
12426				var $closestSub = $(e.target).closest('ul');
12427				while ($closestSub.dataSM('in-mega')) {
12428					$closestSub = $closestSub.parent().closest('ul');
12429				}
12430				if ($closestSub[0] == $sub[0]) {
12431					var up = (e.originalEvent.wheelDelta || -e.originalEvent.detail) > 0;
12432					if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) {
12433						this.menuScroll($sub, up, true);
12434					}
12435				}
12436				e.preventDefault();
12437			},
12438			menuScrollOut: function($sub, e) {
12439				var reClass = /^scroll-(up|down)/,
12440					$closestSub = $(e.relatedTarget).closest('ul');
12441				while ($closestSub.dataSM('in-mega')) {
12442					$closestSub = $closestSub.parent().closest('ul');
12443				}
12444				if (!reClass.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || $closestSub[0] != $sub[0])) {
12445					$sub.dataSM('scroll-arrows').css('visibility', 'hidden');
12446				}
12447			},
12448			menuScrollOver: function($sub, e) {
12449				var reClass = /^scroll-(up|down)/,
12450					$closestSub = $(e.target).closest('ul');
12451				while ($closestSub.dataSM('in-mega')) {
12452					$closestSub = $closestSub.parent().closest('ul');
12453				}
12454				if (!reClass.test(e.target.className) && $closestSub[0] == $sub[0]) {
12455					$sub.dataSM('scroll-arrows').css('visibility', 'visible');
12456				}
12457			},
12458			menuScrollStop: function($sub) {
12459				if (this.scrollTimeout) {
12460					clearTimeout(this.scrollTimeout);
12461					this.scrollTimeout = 0;
12462					$sub.dataSM('scroll').step = 1;
12463				}
12464			},
12465			menuShow: function($sub) {
12466				if (!$sub.dataSM('beforefirstshowfired')) {
12467					$sub.dataSM('beforefirstshowfired', true);
12468					if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) {
12469						return;
12470					}
12471				}
12472				if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) {
12473					return;
12474				}
12475				this.menuFixLayout($sub);
12476				$sub.stop(true, true);
12477				if (!$sub.is(':visible')) {
12478					$sub.css({
12479						'visibility': 'visible',
12480						'pointer-events': 'auto',
12481					});
12482					// set z-index - for IE < 9 set it to the parent LI
12483					var zIndex = this.getStartZIndex() + (++this.zIndexInc);
12484					if (IElt9) {
12485						$sub.parent().css('z-index', zIndex);
12486					} else {
12487						$sub.css('z-index', zIndex);
12488					}
12489					// highlight parent item
12490					if (this.opts.keepHighlighted || this.isCollapsible()) {
12491						if ($sub.dataSM('parent-a').attr('data-type') != 'title')
12492							$sub.dataSM('parent-a').addClass('highlighted');
12493					}
12494					// min/max-width fix - no way to rely purely on CSS as all UL's are nested
12495					if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) {
12496						if (!IElt8) {
12497							$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
12498							if (this.opts.subMenusMinWidth) {
12499							 	$sub.css('min-width', this.opts.subMenusMinWidth);
12500							}
12501							if (this.opts.subMenusMaxWidth) {
12502							 	var noMaxWidth = this.getWidth($sub);
12503							 	if ( ! $sub.hasClass('mega-menu-inner') ) {
12504								 	$sub.css('max-width', this.opts.subMenusMaxWidth);
12505							 	}
12506								if (noMaxWidth > this.getWidth($sub)) {
12507									$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
12508								}
12509							}
12510						// IE6,7
12511 						} else {
12512							$sub.children().css('styleFloat', 'none');
12513							if (IE6) {
12514								$sub.width(this.opts.subMenusMinWidth ? this.opts.subMenusMinWidth : 1)
12515									.children().children('a').css('white-space', 'nowrap');
12516							} else { // IE7
12517								$sub.css({ width: ($sub.hasClass('mega-menu-inner')) ? $('.box-container').outerWidth() + 'px' : 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap');
12518								if (this.opts.subMenusMinWidth) {
12519									$sub.css('min-width', this.opts.subMenusMinWidth);
12520								}
12521							}
12522							if (this.opts.subMenusMaxWidth) {
12523								var noMaxWidth = $sub.width();
12524								if (IE6) {
12525							 		var maxWidth = $sub.css({ width: this.opts.subMenusMaxWidth, overflowX: 'hidden', overflowY: 'hidden' }).width();
12526									if (noMaxWidth > maxWidth) {
12527										$sub.css({ width: maxWidth, overflowX: 'visible', overflowY: 'visible' }).children().children('a').css('white-space', '');
12528									} else {
12529										$sub.css({ width: noMaxWidth, overflowX: 'visible', overflowY: 'visible' });
12530									}
12531								} else { // IE7
12532								 	if ( ! $sub.hasClass('mega-menu-inner') ) {
12533									 	$sub.css('max-width', this.opts.subMenusMaxWidth);
12534								 	}
12535									if (noMaxWidth > $sub.width()) {
12536										$sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth);
12537									} else {
12538										$sub.width(noMaxWidth);
12539									}
12540								}
12541							} else {
12542							 	$sub.width($sub.width());
12543							}
12544							$sub.children().css('styleFloat', 'left');
12545						}
12546					}
12547					this.menuPosition($sub);
12548					// insert IE iframe shim
12549					if ($sub.dataSM('ie-shim')) {
12550						$sub.dataSM('ie-shim').insertBefore($sub);
12551					}
12552					var complete = function() {
12553						// fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used
12554						$sub.css('overflow', '');
12555					};
12556					// if sub is collapsible (mobile view)
12557					if (this.isCollapsible()) {
12558						if (this.opts.collapsibleShowFunction) {
12559							this.opts.collapsibleShowFunction.call(this, $sub, complete);
12560						} else {
12561							$sub.show(this.opts.collapsibleShowDuration, complete);
12562						}
12563					} else {
12564						if (this.opts.showFunction) {
12565							this.opts.showFunction.call(this, $sub, complete);
12566						} else {
12567							$sub.show(this.opts.showDuration, complete);
12568						}
12569					}
12570					// save new sub menu for this level
12571					this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub;
12572					this.$root.triggerHandler('show.smapi', $sub[0]);
12573				}
12574			},
12575			popupHide: function(noHideTimeout) {
12576				if (this.hideTimeout) {
12577					clearTimeout(this.hideTimeout);
12578					this.hideTimeout = 0;
12579				}
12580				var self = this;
12581				this.hideTimeout = setTimeout(function() {
12582					self.menuHideAll();
12583				}, noHideTimeout ? 1 : this.opts.hideTimeout);
12584			},
12585			popupShow: function(left, top) {
12586				if (!this.opts.isPopup) {
12587					alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.');
12588					return;
12589				}
12590				if (this.hideTimeout) {
12591					clearTimeout(this.hideTimeout);
12592					this.hideTimeout = 0;
12593				}
12594				this.menuFixLayout(this.$root);
12595				this.$root.stop(true, true);
12596				if (!this.$root.is(':visible')) {
12597					this.$root.css({ left: left, top: top });
12598					// IE iframe shim
12599					this.menuIframeShim(this.$root);
12600					if (this.$root.dataSM('ie-shim')) {
12601						this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left
12601: left, top: top }).insertBefore(this.$root);
12602					}
12603					// show menu
12604					if (this.opts.showFunction) {
12605						this.opts.showFunction.call(this, this.$root);
12606					} else {
12607						this.$root.show(this.opts.showDuration);
12608					}
12609					this.visibleSubMenus[0] = this.$root;
12610				}
12611			},
12612			refresh: function() {
12613				this.menuHideAll();
12614				this.$root.find('ul').each(function() {
12615						var $this = $(this);
12616						if ($this.dataSM('scroll-arrows')) {
12617							$this.dataSM('scroll-arrows').remove();
12618						}
12619					})
12620					.removeDataSM('in-mega')
12621					.removeDataSM('shown-before')
12622					.removeDataSM('ie-shim')
12623					.removeDataSM('scroll-arrows')
12624					.removeDataSM('parent-a')
12625					.removeDataSM('level')
12626					.removeDataSM('beforefirstshowfired');
12627				this.$root.find('a.has-submenu').removeClass('has-submenu')
12628					.parent().removeDataSM('sub');
12629				if (this.opts.subIndicators) {
12630					this.$root.find('span.sub-arrow').remove();
12631				}
12632				if (this.opts.markCurrentItem) {
12633					this.$root.find('a.current').removeClass('current');
12634				}
12635				this.subMenus = [];
12636				this.init(true);
12637			},
12638			rootOut: function(e) {
12639				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
12640					return;
12641				}
12642				if (this.hideTimeout) {
12643					clearTimeout(this.hideTimeout);
12644					this.hideTimeout = 0;
12645				}
12646				if (!this.opts.showOnClick || !this.opts.hideOnClick) {
12647					var self = this;
12648					this.hideTimeout = setTimeout(function() { self.menuHideAll(); }, this.opts.hideTimeout);
12649				}
12650			},
12651			rootOver: function(e) {
12652				if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) {
12653					return;
12654				}
12655				if (this.hideTimeout) {
12656					clearTimeout(this.hideTimeout);
12657					this.hideTimeout = 0;
12658				}
12659			},
12660			winResize: function(e) {
12661				if (!this.handleEvents()) {
12662					// we still need to resize the disable overlay if it's visible
12663					if (this.$disableOverlay) {
12664						var pos = this.$root.offset();
12665	 					this.$disableOverlay.css({
12666							top: pos.top,
12667							left: pos.left,
12668							width: this.$root.outerWidth(),
12669							height: this.$root.outerHeight()
12670						});
12671					}
12672					return;
12673				}
12674				// hide sub menus on resize - on mobile do it only on orientation change
12675				if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) {
12676					if (this.activatedItems.length) {
12677						this.activatedItems[this.activatedItems.length - 1][0].blur();
12678					}
12679					this.menuHideAll();
12680				}
12681			}
12682		}
12683	});
12684
12685	$.fn.dataSM = function(key, val) {
12686		if (val) {
12687			return this.data(key + '_smartmenus', val);
12688		}
12689		return this.data(key + '_smartmenus');
12690	}
12691
12692	$.fn.removeDataSM = function(key) {
12693		return this.removeData(key + '_smartmenus');
12694	}
12695
12696	$.fn.smartmenus = function(options) {
12697		if (typeof options == 'string') {
12698			var args = arguments,
12699				method = options;
12700			Array.prototype.shift.call(args);
12701			return this.each(function() {
12702				var smartmenus = $(this).data('smartmenus');
12703				if (smartmenus && smartmenus[method]) {
12704					smartmenus[method].apply(smartmenus, args);
12705				}
12706			});
12707		}
12708		var opts = $.extend({}, $.fn.smartmenus.defaults, options);
12709		return this.each(function() {
12710			new $.SmartMenus(this, opts);
12711		});
12712	}
12713
12714	// default settings
12715	$.fn.smartmenus.defaults = {
12716		isPopup:		false,		// is this a popup menu (can be shown via the popupShow/popupHide methods) or a permanent menu bar
12717		mainMenuSubOffsetX:	0,		// pixels offset from default position
12718		mainMenuSubOffsetY:	0,		// pixels offset from default position
12719		subMenusSubOffsetX:	0,		// pixels offset from default position
12720		subMenusSubOffsetY:	0,		// pixels offset from default position
12721		subMenusMinWidth:	'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
12722		subMenusMaxWidth:	'20em',		// max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
12723		subIndicators: 		true,		// create sub menu indicators - creates a SPAN and inserts it in the A
12724		subIndicatorsPos: 	'prepend',	// position of the SPAN relative to the menu item content ('prepend', 'append')
12725		subIndicatorsText:	'+',		// [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too)
12726		scrollStep: 		30,		// pixels step when scrolling long sub menus that do not fit in the viewport height
12727		scrollInterval:		30,		// interval between each scrolling step
12728		scrollAccelerate:	true,		// accelerate scrolling or use a fixed step
12729		showTimeout:		250,		// timeout before showing the sub menus
12730		hideTimeout:		500,		// timeout before hiding the sub menus
12731		showDuration:		0,		// duration for show animation - set to 0 for no animation - matters only if showFunction:null
12732		showFunction:		null,		// custom function to use when showing a sub menu (the default is the jQuery 'show')
12733							// don't forget to call complete() at the end of whatever you do
12734							// e.g.: function($ul, complete) { $ul.fadeIn(250, complete); }
12735		hideDuration:		0,		// duration for hide animation - set to 0 for no animation - matters only if hideFunction:null
12736		hideFunction:		function($ul, complete) { $ul.fadeOut(200, complete); },	// custom function to use when hiding a sub menu (the default is the jQuery 'hide')
12737							// don't forget to call complete() at the end of whatever you do
12738							// e.g.: function($ul, complete) { $ul.fadeOut(250, complete); }
12739		collapsibleShowDuration:0,		// duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null
12740		collapsibleShowFunction:function($ul, complete) { $ul.slideDown(200, complete); },	// custom function to use when showing a collapsible sub menu
12741							// (i.e. when mobile styles are used to make the sub menus collapsible)
12742		collapsibleHideDuration:0,		// duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null
12743		collapsibleHideFunction:function($ul, complete) { $ul.slideUp(200, complete); },	// custom function to use when hiding a collapsible sub menu
12744							// (i.e. when mobile styles are used to make the sub menus collapsible)
12745		showOnClick:		false,		// show the first-level sub menus onclick instead of onmouseover (matters only for mouse input)
12746		hideOnClick:		true,		// hide the sub menus on click/tap anywhere on the page
12747		keepInViewport:		true,		// reposition the sub menus if needed to make sure they always appear inside the viewport
12748		keepHighlighted:	true,		// keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's)
12749		markCurrentItem:	false,		// automatically add the 'current' class to the A element of the item linking to the current URL
12750		markCurrentTree:	true,		// add the 'current' class also to the A elements of all ancestor items of the current item
12751		rightToLeftSubMenus:	false,		// right to left display of the sub menus (check the CSS for the sub indicators' position)
12752		bottomToTopSubMenus:	false,		// bottom to top display of the sub menus
12753		overlapControlsInIE:	true		// make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.)
12754	};
12755
12756})(jQuery);
12757
12758/*
12759 * jQuery Easing v1.4.1 - http://gsgd.co.uk/sandbox/jquery/easing/
12760 * Open source under the BSD License.
12761 * Copyright © 2008 George McGinley Smith
12762 * All rights reserved.
12763 * https://raw.github.com/gdsmith/jquery.easing/master/LICENSE
12764*/
12765
12766/* globals jQuery, define, module, require */
12767(function (factory) {
12768	if (typeof define === "function" && define.amd) {
12769		define(['jquery'], function ($) {
12770			return factory($);
12771		});
12772	} else if (typeof module === "object" && typeof module.exports === "object") {
12773		module.exports = factory(require('jquery'));
12774	} else {
12775		factory(jQuery);
12776	}
12777})(function($){
12778
12779	// Preserve the original jQuery "swing" easing as "jswing"
12780	if (typeof $.easing !== 'undefined') {
12781		$.easing['jswing'] = $.easing['swing'];
12782	}
12783
12784	var pow = Math.pow,
12785		sqrt = Math.sqrt,
12786		sin = Math.sin,
12787		cos = Math.cos,
12788		PI = Math.PI,
12789		c1 = 1.70158,
12790		c2 = c1 * 1.525,
12791		c3 = c1 + 1,
12792		c4 = ( 2 * PI ) / 3,
12793		c5 = ( 2 * PI ) / 4.5;
12794
12795	// x is the fraction of animation progress, in the range 0..1
12796	function bounceOut(x) {
12797		var n1 = 7.5625,
12798			d1 = 2.75;
12799		if ( x < 1/d1 ) {
12800			return n1*x*x;
12801		} else if ( x < 2/d1 ) {
12802			return n1*(x-=(1.5/d1))*x + .75;
12803		} else if ( x < 2.5/d1 ) {
12804			return n1*(x-=(2.25/d1))*x + .9375;
12805		} else {
12806			return n1*(x-=(2.625/d1))*x + .984375;
12807		}
12808	}
12809
12810	$.extend( $.easing, {
12811		def: 'easeOutQuad',
12812		swing: function (x) {
12813			return $.easing[$.easing.def](x);
12814		},
12815		easeInQuad: function (x) {
12816			return x * x;
12817		},
12818		easeOutQuad: function (x) {
12819			return 1 - ( 1 - x ) * ( 1 - x );
12820		},
12821		easeInOutQuad: function (x) {
12822			return x < 0.5 ?
12823				2 * x * x :
12824				1 - pow( -2 * x + 2, 2 ) / 2;
12825		},
12826		easeInCubic: function (x) {
12827			return x * x * x;
12828		},
12829		easeOutCubic: function (x) {
12830			return 1 - pow( 1 - x, 3 );
12831		},
12832		easeInOutCubic: function (x) {
12833			return x < 0.5 ?
12834				4 * x * x * x :
12835				1 - pow( -2 * x + 2, 3 ) / 2;
12836		},
12837		easeInQuart: function (x) {
12838			return x * x * x * x;
12839		},
12840		easeOutQuart: function (x) {
12841			return 1 - pow( 1 - x, 4 );
12842		},
12843		easeInOutQuart: function (x) {
12844			return x < 0.5 ?
12845				8 * x * x * x * x :
12846				1 - pow( -2 * x + 2, 4 ) / 2;
12847		},
12848		easeInQuint: function (x) {
12849			return x * x * x * x * x;
12850		},
12851		easeOutQuint: function (x) {
12852			return 1 - pow( 1 - x, 5 );
12853		},
12854		easeInOutQuint: function (x) {
12855			return x < 0.5 ?
12856				16 * x * x * x * x * x :
12857				1 - pow( -2 * x + 2, 5 ) / 2;
12858		},
12859		easeInSine: function (x) {
12860			return 1 - cos( x * PI/2 );
12861		},
12862		easeOutSine: function (x) {
12863			return sin( x * PI/2 );
12864		},
12865		easeInOutSine: function (x) {
12866			return -( cos( PI * x ) - 1 ) / 2;
12867		},
12868		easeInExpo: function (x) {
12869			return x === 0 ? 0 : pow( 2, 10 * x - 10 );
12870		},
12871		easeOutExpo: function (x) {
12872			return x === 1 ? 1 : 1 - pow( 2, -10 * x );
12873		},
12874		easeInOutExpo: function (x) {
12875			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
12876				pow( 2, 20 * x - 10 ) / 2 :
12877				( 2 - pow( 2, -20 * x + 10 ) ) / 2;
12878		},
12879		easeInCirc: function (x) {
12880			return 1 - sqrt( 1 - pow( x, 2 ) );
12881		},
12882		easeOutCirc: function (x) {
12883			return sqrt( 1 - pow( x - 1, 2 ) );
12884		},
12885		easeInOutCirc: function (x) {
12886			return x < 0.5 ?
12887				( 1 - sqrt( 1 - pow( 2 * x, 2 ) ) ) / 2 :
12888				( sqrt( 1 - pow( -2 * x + 2, 2 ) ) + 1 ) / 2;
12889		},
12890		easeInElastic: function (x) {
12891			return x === 0 ? 0 : x === 1 ? 1 :
12892				-pow( 2, 10 * x - 10 ) * sin( ( x * 10 - 10.75 ) * c4 );
12893		},
12894		easeOutElastic: function (x) {
12895			return x === 0 ? 0 : x === 1 ? 1 :
12896				pow( 2, -10 * x ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1;
12897		},
12898		easeInOutElastic: function (x) {
12899			return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ?
12900				-( pow( 2, 20 * x - 10 ) * sin( ( 20 * x - 11.125 ) * c5 )) / 2 :
12901				pow( 2, -20 * x + 10 ) * sin( ( 20 * x - 11.125 ) * c5 ) / 2 + 1;
12902		},
12903		easeInBack: function (x) {
12904			return c3 * x * x * x - c1 * x * x;
12905		},
12906		easeOutBack: function (x) {
12907			return 1 + c3 * pow( x - 1, 3 ) + c1 * pow( x - 1, 2 );
12908		},
12909		easeInOutBack: function (x) {
12910			return x < 0.5 ?
12911				( pow( 2 * x, 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2 :
12912				( pow( 2 * x - 2, 2 ) *( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2;
12913		},
12914		easeInBounce: function (x) {
12915			return 1 - bounceOut( 1 - x );
12916		},
12917		easeOutBounce: bounceOut,
12918		easeInOutBounce: function (x) {
12919			return x < 0.5 ?
12920				( 1 - bounceOut( 1 - 2 * x ) ) / 2 :
12921				( 1 + bounceOut( 2 * x - 1 ) ) / 2;
12922		}
12923	});
12924	return $;
12925});
12926
12927/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
12928 * Licensed under the MIT License (LICENSE.txt).
12929 *
12930 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
12931 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
12932 * Thanks to: Seamus Leahy for adding deltaX and deltaY
12933 *
12934 * Version: 3.0.6
12935 *
12936 * Requires: 1.2.2+
12937 */
12938(function($) {
12939    var types = ['DOMMouseScroll', 'mousewheel'];
12940    if ($.event.fixHooks) {
12941        for (var i = types.length; i;) {
12942            $.event.fixHooks[types[--i]] = $.event.mouseHooks;
12943        }
12944    }
12945    $.event.special.mousewheel = {
12946        setup: function() {
12947            if (this.addEventListener) {
12948                for (var i = types.length; i;) {
12949                    this.addEventListener(types[--i], handler, false);
12950                }
12951            } else {
12952                this.onmousewheel = handler;
12953            }
12954        },
12955        teardown: function() {
12956            if (this.removeEventListener) {
12957                for (var i = types.length; i;) {
12958                    this.removeEventListener(types[--i], handler, false);
12959                }
12960            } else {
12961                this.onmousewheel = null;
12962            }
12963        }
12964    };
12965    $.fn.extend({
12966        mousewheel: function(fn) {
12967            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
12968        },
12969        unmousewheel: function(fn) {
12970            return this.unbind("mousewheel", fn);
12971        }
12972    });
12973
12974    function handler(event) {
12975        var orgEvent = event || window.event,
12976            args = [].slice.call(arguments, 1),
12977            delta = 0,
12978            returnValue = true,
12979            deltaX = 0,
12980            deltaY = 0;
12981        event = $.event.fix(orgEvent);
12982        event.type = "mousewheel";
12983        // Old school scrollwheel delta
12984        if (orgEvent.wheelDelta) {
12985            delta = orgEvent.wheelDelta / 120;
12986        }
12987        if (orgEvent.detail) {
12988            delta = -orgEvent.detail / 3;
12989        }
12990        // New school multidimensional scroll (touchpads) deltas
12991        deltaY = delta;
12992        // Gecko
12993        if (orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
12994            deltaY = 0;
12995            deltaX = -1 * delta;
12996        }
12997        // Webkit
12998        if (orgEvent.wheelDeltaY !== undefined) {
12999            deltaY = orgEvent.wheelDeltaY / 120;
13000        }
13001        if (orgEvent.wheelDeltaX !== undefined) {
13002            deltaX = -1 * orgEvent.wheelDeltaX / 120;
13003        }
13004        // Add event and delta to the front of the arguments
13005        args.unshift(event, delta, deltaX, deltaY);
13006        return ($.event.dispatch || $.event.handle).apply(this, args);
13007    }
13008})(jQuery);
13009/**
13010 * jQuery iLightBox - Revolutionary Lightbox Plugin
13011 * http://www.ilightbox.net/
13012 *
13013 * @version: 2.2.4 - October 14, 2017
13014 *
13015 * @author: iProDev (Hemn Chawroka)
13016 *          http://www.iprodev.com/
13017 *
13018 */
13019(function($, window, undefined) {
13020
13021	var extensions = {
13022			flash: ['swf'],
13023			image: ['bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff', 'tif', 'jfif', 'jpe', 'webp'],
13024			iframe: ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'jsp', 'php', 'pl', 'php3', 'php4', 'php5', 'phtml', 'rb', 'rhtml', 'shtml', 'txt'],
13025			video: ['avi', 'mov', 'mpg', 'mpeg', 'movie', 'mp4', 'webm', 'ogv', 'ogg', '3gp', 'm4v']
13026		},
13027
13028		// Global DOM elements
13029		$win = $(window),
13030		$doc = $(document),
13031
13032		// Support indicators
13033		browser,
13034		transform,
13035		gpuAcceleration,
13036		fullScreenApi = '',
13037		userAgent = navigator.userAgent || navigator.vendor || window.opera,
13038        supportTouch = "ontouchstart" in window || navigator.msMaxTouchPoints || (navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1),
13039        ishybrid = navigator.maxTouchPoints && navigator.userAgent.indexOf('Windows') > -1,
13040        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)),
13041
13042		// Events
13043		clickEvent = ishybrid ? "itap.iLightBox click.iLightBox" : supportTouch ? "itap.iLightBox" : "click.iLightBox",
13044		touchStartEvent = ishybrid ? "touchstart.iLightBox mousedown.iLightBox" : supportTouch ? "touchstart.iLightBox" : "mousedown.iLightBox",
13045		touchStopEvent = ishybrid ? "touchend.iLightBox mouseup.iLightBox" : supportTouch ? "touchend.iLightBox" : "mouseup.iLightBox",
13046		touchMoveEvent = ishybrid ? "touchmove.iLightBox mousemove.iLightBox" : supportTouch ? "touchmove.iLightBox" : "mousemove.iLightBox",
13047
13048		// Math shorthands
13049		abs = Math.abs,
13050		sqrt = Math.sqrt,
13051		round = Math.round,
13052		max = Math.max,
13053		min = Math.min,
13054		floor = Math.floor,
13055		random = Math.random,
13056
13057		pluginspages = {
13058			quicktime: 'http://www.apple.com/quicktime/download',
13059			flash: 'http://www.adobe.com/go/getflash'
13060		},
13061
13062		iLightBox = function(el, options, items, instant) {
13063			var iL = this;
13064
13065			iL.options = options,
13066				iL.selector = options.selector || el,
13067				iL.context = document,
13068				iL.instant = instant;
13069
13070			if (items.length < 1) iL.attachItems();
13071			else iL.items = items;
13072
13073			iL.vars = {
13074				total: iL.items.length,
13075				start: 0,
13076				current: null,
13077				next: null,
13078				prev: null,
13079				BODY: $('body'),
13080				loadRequests: 0,
13081				overlay: $('<div class="ilightbox-overlay"></div>'),
13082				loader: $('<div class="ilightbox-loader"><div></div></div>'),
13083				toolbar: $('<div class="ilightbox-toolbar"></div>'),
13084				innerToolbar: $('<div class="ilightbox-inner-toolbar"></div>'),
13085				title: $('<div class="ilightbox-title"></div>'),
13086				closeButton: $('<a class="ilightbox-close" title="' + iL.options.text.close + '"></a>'),
13087				fullScreenButton: $('<a class="ilightbox-fullscreen" title="' + iL.options.text.enterFullscreen + '"></a>'),
13088				innerPlayButton: $('<a class="ilightbox-play" title="' + iL.options.text.slideShow + '"></a>'),
13089				innerNextButton: $('<a class="ilightbox-next-button" title="' + iL.options.text.next + '"></a>'),
13090				innerPrevButton: $('<a class="ilightbox-prev-button" title="' + iL.options.text.previous + '"></a>'),
13091				holder: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + '" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
13092				nextPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-next" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
13093				prevPhoto: $('<div class="ilightbox-holder' + (supportTouch ? ' supportTouch' : '') + ' ilightbox-prev" ondragstart="return false;"><div class="ilightbox-container"></div></div>'),
13094				nextButton: $('<a class="ilightbox-button ilightbox-next-button" ondragstart="return false;" title="' + iL.options.text.next + '"><span></span></a>'),
13095				prevButton: $('<a class="ilightbox-button ilightbox-prev-button" ondragstart="return false;" title="' + iL.options.text.previous + '"><span></span></a>'),
13096				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>'),
13097				thumbs: false,
13098				nextLock: false,
13099				prevLock: false,
13100				hashLock: false,
13101				isMobile: false,
13102				mobileMaxWidth: 980,
13103				isInFullScreen: false,
13104				isSwipe: false,
13105				mouseID: 0,
13106				cycleID: 0,
13107				isPaused: 0,
13108				captionHeight: 39,
13109			};
13110
13111			// Hideable elements with mousemove event
13112			iL.vars.hideableElements = iL.vars.nextButton.add(iL.vars.prevButton);
13113
13114			iL.normalizeItems();
13115
13116			//Check necessary plugins
13117			iL.availPlugins();
13118
13119			//Set startFrom
13120			iL.options.startFrom = (iL.options.startFrom > 0 && iL.options.startFrom >= iL.vars.total) ? iL.vars.total - 1 : iL.options.startFrom;
13121
13122			//If randomStart
13123			iL.options.startFrom = (iL.options.randomStart) ? floor(random() * iL.vars.total) : iL.options.startFrom;
13124			iL.vars.start = iL.options.startFrom;
13125
13126			if (instant) iL.instantCall();
13127			else iL.patchItemsEvents();
13128
13129			if (iL.options.linkId) {
13130				iL.hashChangeHandler();
13131				$win.iLightBoxHashChange(function() {
13132					iL.hashChangeHandler();
13133				});
13134			}
13135
13136			if (supportTouch) {
13137				var RegExp = /(click|mouseenter|mouseleave|mouseover|mouseout)/ig,
13138					replace = "itap";
13139				iL.options.caption.show = iL.options.caption.show.replace(RegExp, replace),
13140					iL.options.caption.hide = iL.options.caption.hide.replace(RegExp, replace),
13141					iL.options.social.show = iL.options.social.show.replace(RegExp, replace),
13142					iL.options.social.hide = iL.options.social.hide.replace(RegExp, replace);
13143			}
13144
13145			if (iL.options.controls.arrows || $(window).width() < UNCODE.mediaQuery) {
13146				$.extend(iL.options.styles, {
13147					nextOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
13148					prevOffsetX: ($(window).width() > UNCODE.mediaQuery) ? 36 : 4,
13149					nextOpacity: 0,
13150					prevOpacity: 0
13151				});
13152			}
13153		};
13154
13155	//iLightBox helpers
13156	iLightBox.prototype = {
13157		showLoader: function() {
13158			var iL = this;
13159			iL.vars.loadRequests += 1;
13160			if (iL.options.path.toLowerCase() == "horizontal") iL.vars.loader.addClass('ilightbox-show').stop().animate({
13161				//top: '-30px'
13162				opacity: '1'
13163			}, iL.options.show.speed, 'easeOutCirc');
13164			else iL.vars.loader.addClass('ilightbox-show').stop().animate({
13165				//left: '-30px'
13166				opacity: '1'
13167			}, iL.options.show.speed, 'easeOutCirc');
13168		},
13169
13170		hideLoader: function() {
13171			var iL = this;
13172			iL.vars.loadRequests -= 1;
13173			iL.vars.loadRequests = (iL.vars.loadRequests < 0) ? 0 : iL.vars.loadRequests;
13174			if (iL.options.path.toLowerCase() == "horizontal") {
13175				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
13176					//top: '-192px'
13177					opacity: '0'
13178				}, iL.options.show.speed, 'easeInCirc');
13179			} else {
13180				if (iL.vars.loadRequests <= 0) iL.vars.loader.removeClass('ilightbox-show').stop().animate({
13181					//left: '-192px'
13182					opacity: '0'
13183				}, iL.options.show.speed, 'easeInCirc');
13184			}
13185		},
13186
13187		createUI: function() {
13188			var iL = this;
13189
13190			iL.ui = {
13191				currentElement: iL.vars.holder,
13192				nextElement: iL.vars.nextPhoto,
13193				prevElement: iL.vars.prevPhoto,
13194				currentItem: iL.vars.current,
13195				nextItem: iL.vars.next,
13196				prevItem: iL.vars.prev,
13197				hide: function() {
13198					iL.closeAction();
13199				},
13200				refresh: function() {
13201					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
13202				},
13203				fullscreen: function() {
13204					iL.fullScreenAction();
13205				}
13206			};
13207		},
13208
13209		attachItems: function() {
13210			var iL = this,
13211				itemsObject = new Array(),
13212				items = new Array();
13213
13214			$(iL.selector, iL.context).each(function() {
13215				var t = $(this),
13216					URL = t.attr(iL.options.attr) || null,
13217					options = t.data("options") && eval("({" + t.data("options") + "})") || {},
13218					caption = t.data('caption'),
13219					title = t.data('title'),
13220					type = t.data('type') || getTypeByExtension(URL),
13221					clone = t.data('lbox-clone') || false;
13222
13223				//Uncode addition ##START##
13224				if (type === false) {
13225					return;
13226				}
13227				//Uncode addition ##END##
13228
13229				if (t.data('lbox-clone') != undefined) return;
13230
13231				//Uncode addition ##START##
13232				if ( typeof t.attr('data-album') != 'undefined' && t.attr('data-album') != '' ) {
13233					var ALBUM_URLS = JSON.parse(t.attr('data-album')),
13234						URL_i,
13235						URLS_LENGHT = ALBUM_URLS.length;
13236
13237					for (URL_i = 0; URL_i < URLS_LENGHT; URL_i++) {
13238						if ( typeof ALBUM_URLS[URL_i].url !== 'undefined' && ALBUM_URLS[URL_i].url != '' ) {
13239							var item_opts = 'width:' + ALBUM_URLS[URL_i].width + ',height:' + ALBUM_URLS[URL_i].height + ',thumbnail: \'' + ALBUM_URLS[URL_i].thumbnail + '\'';
13240							item_opts = item_opts && eval("({" + item_opts + "})") || {},
13241							items.push({
13242								URL: ALBUM_URLS[URL_i].url,
13243								caption: ALBUM_URLS[URL_i].caption,
13244								title: ALBUM_URLS[URL_i].title,
13245								type: getTypeByExtension(ALBUM_URLS[URL_i].url),
13246								options: item_opts,
13247								clone: clone
13248							});
13249							var newT = t;
13250							newT.attr('href',ALBUM_URLS[URL_i].url);
13251							if (!iL.instant) itemsObject.push(newT);
13252						}
13253					}
13254				} else {
13255				//Uncode addition ##END##
13256					items.push({
13257						URL: URL,
13258						caption: caption,
13259						title: title,
13260						type: type,
13261						options: options,
13262						clone: clone
13263					});
13264				}
13265
13266
13267				if (iL.vars != undefined) iL.vars.total = items.length;
13268
13269				if (!iL.instant) itemsObject.push(t);
13270			});
13271
13272			iL.items = items,
13273				iL.itemsObject = itemsObject;
13274
13275		},
13276
13277		normalizeItems: function() {
13278			var iL = this,
13279				newItems = new Array();
13280
13281			$.each(iL.items, function(key, val) {
13282
13283				if (typeof val == "string") val = {
13284					url: val
13285				};
13286
13287				var URL = val.url || val.URL || null,
13288					options = val.options || {},
13289					caption = val.caption || null,
13290					title = val.title || null,
13291					type = (val.type) ? val.type.toLowerCase() : getTypeByExtension(URL),
13292					ext = (typeof URL != 'object') ? getExtension(URL) : '';
13293
13294				options.thumbnail = options.thumbnail || ((type == "image") ? URL : null),
13295				options.videoType = options.videoType || null,
13296				options.skin = options.skin || iL.options.skin,
13297				options.width = options.width || null,
13298				options.height = options.height || null,
13299				options.mousewheel = (typeof options.mousewheel != 'undefined') ? options.mousewheel : true,
13300				options.swipe = (typeof options.swipe != 'undefined') ? options.swipe : true,
13301				options.social = (typeof options.social != 'undefined') ? options.social : iL.options.social.buttons && $.extend({}, {}, iL.options.social.buttons);
13302
13303				if (type == "video") {
13304					options.html5video = (typeof options.html5video != 'undefined') ? options.html5video : {};
13305
13306					options.html5video.webm = options.html5video.webm || options.html5video.WEBM || null;
13307					options.html5video.controls = (typeof options.html5video.controls != 'undefined') ? options.html5video.controls : "controls";
13308					options.html5video.preload = options.html5video.preload || "metadata";
13309					options.html5video.autoplay = (typeof options.html5video.autoplay != 'undefined') ? options.html5video.autoplay : false;
13310					//UNCODE addition
13311					options.html5video.loop = (typeof options.html5video.loop != 'undefined') ? options.html5video.loop : false;
13312				}
13313
13314				if (!options.width || !options.height) {
13315					if (type == "video") options.width = 1280, options.height = 720;
13316					else if (type == "iframe") options.width = '100%', options.height = '90%';
13317					else if (type == "flash") options.width = 1280, options.height = 720;
13318				}
13319
13320				delete val.url;
13321				val.index = key;
13322				val.URL = URL;
13323				val.caption = caption;
13324				val.title = title;
13325				val.type = type;
13326				val.options = options;
13327				val.ext = ext;
13328
13329				newItems.push(val);
13330			});
13331
13332			iL.items = newItems;
13333		},
13334
13335		instantCall: function() {
13336			var iL = this,
13337				key = iL.vars.start;
13338
13339			iL.vars.current = key;
13340			iL.vars.next = (iL.items[key + 1]) ? key + 1 : null;
13341			iL.vars.prev = (iL.items[key - 1]) ? key - 1 : null;
13342
13343			iL.addContents();
13344			iL.patchEvents();
13345		},
13346
13347		addContents: function() {
13348			var iL = this,
13349				vars = iL.vars,
13350				opts = iL.options,
13351				viewport = getViewport(),
13352				path = opts.path.toLowerCase(),
13353				recognizingItems = vars.total > 0 && iL.items.filter(function(e, i, arr) {
13354					return ['image', 'flash', 'video'].indexOf(e.type) === -1 && typeof e.recognized === 'undefined' && (opts.smartRecognition || e.options.smartRecognition);
13355				}),
13356				needRecognition = recognizingItems.length > 0;
13357
13358			if (opts.mobileOptimizer && !opts.innerToolbar)
13359				vars.isMobile = viewport.width <= vars.mobileMaxWidth;
13360
13361			vars.overlay.addClass(opts.skin).hide().css('opacity', opts.overlay.opacity);
13362
13363			if (opts.linkId)
13364				vars.overlay[0].setAttribute('linkid', opts.linkId);
13365
13366			//Add Toolbar Buttons
13367			if (opts.controls.toolbar) {
13368				vars.toolbar.addClass(opts.skin).append(vars.closeButton);
13369				if (opts.controls.fullscreen)
13370					vars.toolbar.append(vars.fullScreenButton);
13371				if (opts.controls.slideshow)
13372					vars.toolbar.append(vars.innerPlayButton);
13373				if (vars.total > 1)
13374					vars.toolbar.append(vars.innerPrevButton).append(vars.innerNextButton);
13375			}
13376
13377			//Append elements to body
13378			vars.BODY.addClass('ilightbox-noscroll').append(vars.overlay).append(vars.loader).append(vars.holder).append(vars.nextPhoto).append(vars.prevPhoto);
13379
13380			if (!opts.innerToolbar)
13381				vars.BODY.append(vars.toolbar);
13382			if (opts.controls.arrows)
13383				vars.BODY.append(vars.nextButton).append(vars.prevButton);
13384
13385			if (opts.controls.thumbnail && vars.total > 1) {
13386				vars.BODY.append(vars.thumbnails);
13387				vars.thumbnails.addClass(opts.skin).addClass('ilightbox-' + path);
13388				$('div.ilightbox-thumbnails-grid', vars.thumbnails).empty();
13389				vars.thumbs = true;
13390			}
13391
13392			//Configure loader and arrows
13393			var loaderCss = (opts.path.toLowerCase() == "horizontal") ? {
13394				left: parseInt((viewport.width / 2) - (vars.loader.outerWidth() / 2))
13395			} : {
13396				top: parseInt((viewport.height / 2) - (vars.loader.outerHeight() / 2))
13397			};
13398			vars.loader.addClass(opts.skin).css(loaderCss);
13399			vars.nextButton.add(vars.prevButton).addClass(opts.skin);
13400			if (path == "horizontal")
13401				vars.loader.add(vars.nextButton).add(vars.prevButton).addClass('horizontal');
13402
13403			// Configure arrow buttons
13404			vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
13405
13406			if (!opts.infinite) {
13407				vars.prevButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
13408
13409				if (vars.current == 0)
13410					vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
13411				if (vars.current >= vars.total - 1)
13412					vars.nextButton.add(vars.innerNextButton).addClass('disabled');
13413			}
13414
13415			if (opts.show.effect) {
13416				vars.overlay.stop().fadeIn(opts.show.speed);
13417				vars.toolbar.stop().fadeIn(opts.show.speed);
13418			} else {
13419				vars.overlay.show();
13420				vars.toolbar.show();
13421			}
13422
13423			var length = recognizingItems.length;
13424			if (needRecognition) {
13425				iL.showLoader();
13426
13427				$.each(recognizingItems, function(key, val) {
13428					var resultFnc = function(result) {
13429							var key = -1,
13430								filter = iL.items.filter(function(e, i, arr) {
13431									if (e.URL == result.url)
13432										key = i;
13433
13434									return e.URL == result.url;
13435								}),
13436								self = iL.items[key];
13437
13438							if (result)
13439								$.extend(true, self, {
13440									URL: result.source,
13441									type: result.type,
13442									recognized: true,
13443									options: {
13444										html5video: result.html5video,
13445										width: (result.type == "image") ? 0 : (result.width || self.width),
13446										height: (result.type == "image") ? 0 : (result.height || self.height),
13447										thumbnail: self.options.thumbnail || result.thumbnail
13448									}
13449								});
13450
13451							length--;
13452
13453							if (length == 0) {
13454								iL.hideLoader();
13455
13456								vars.dontGenerateThumbs = false;
13457								iL.generateThumbnails();
13458
13459								if (opts.show.effect)
13460									setTimeout(function() {
13461										iL.generateBoxes();
13462									}, opts.show.speed);
13463								else
13464									iL.generateBoxes();
13465							}
13466						};
13467
13468					iL.ogpRecognition(this, resultFnc);
13469				});
13470			}
13471			else {
13472				if (opts.show.effect)
13473					setTimeout(function() {
13474						iL.generateBoxes();
13475					}, opts.show.speed);
13476				else
13477					iL.generateBoxes();
13478			}
13479
13480			iL.createUI();
13481
13482			window.iLightBox = {
13483				close: function() {
13484					iL.closeAction();
13485				},
13486				fullscreen: function() {
13487					iL.fullScreenAction();
13488				},
13489				moveNext: function() {
13490					iL.moveTo('next');
13491				},
13492				movePrev: function() {
13493					iL.moveTo('prev');
13494				},
13495				goTo: function(index) {
13496					iL.goTo(index);
13497				},
13498				refresh: function() {
13499					iL.refresh();
13500				},
13501				reposition: function() {
13502					(arguments.length > 0) ? iL.repositionPhoto(true): iL.repositionPhoto();
13503				},
13504				setOption: function(options) {
13505					iL.setOption(options);
13506				},
13507				destroy: function() {
13508					iL.closeAction();
13509					iL.dispatchItemsEvents();
13510				}
13511			};
13512
13513			if (opts.linkId) {
13514				vars.hashLock = true;
13515				window.location.hash = opts.linkId + '/' + vars.current;
13516				setTimeout(function() {
13517					vars.hashLock = false;
13518				}, 55);
13519			}
13520
13521			if (!opts.slideshow.startPaused) {
13522				iL.resume();
13523				vars.innerPlayButton.removeClass('ilightbox-play').addClass('ilightbox-pause');
13524			}
13525
13526			//Trigger the onOpen callback
13527			if (typeof iL.options.callback.onOpen == 'function') iL.options.callback.onOpen.call(iL);
13528		},
13529
13530		loadContent: function(obj, opt, speed) {
13531			var iL = this,
13532				holder, item;
13533
13534			iL.createUI();
13535
13536			obj.speed = speed || iL.options.effects.loadedFadeSpeed;
13537
13538			if (opt == 'current') {
13539				if (!obj.options.mousewheel) iL.vars.lockWheel = true;
13540				else iL.vars.lockWheel = false;
13541
13542				if (!obj.options.swipe) iL.vars.lockSwipe = true;
13543				else iL.vars.lockSwipe = false;
13544			}
13545
13546			switch (opt) {
13547				case 'current':
13548					holder = iL.vars.holder, item = iL.vars.current;
13549					break;
13550				case 'next':
13551					holder = iL.vars.nextPhoto, item = iL.vars.next;
13552					break;
13553				case 'prev':
13554					holder = iL.vars.prevPhoto, item = iL.vars.prev;
13555					break;
13556			}
13557
13558			holder.removeAttr('style class').addClass('ilightbox-holder' + (supportTouch ? ' supportTouch' : '')).addClass(obj.options.skin);
13559			$('div.ilightbox-inner-toolbar', holder).remove();
13560
13561			if (obj.title || iL.options.innerToolbar) {
13562				var innerToolbar = iL.vars.innerToolbar.clone();
13563				if (obj.title && iL.options.show.title) {
13564					var title = iL.vars.title.clone();
13565					title.empty().html(obj.title);
13566					innerToolbar.append(title);
13567				}
13568				if (iL.options.innerToolbar) {
13569					innerToolbar.append((iL.vars.total > 1) ? iL.vars.toolbar.clone() : iL.vars.toolbar);
13570				}
13571				holder.prepend(innerToolbar);
13572			}
13573
13574			//console.warn('loadContent', arguments);
13575
13576			iL.loadSwitcher(obj, holder, item, opt);
13577		},
13578
13579		loadSwitcher: function(obj, holder, item, opt) {
13580			var iL = this,
13581				opts = iL.options,
13582				api = {
13583					element: holder,
13584					position: item
13585				};
13586
13587			switch (obj.type) {
13588				case 'image':
13589					//Trigger the onBeforeLoad callback
13590					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
13591					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
13592
13593					iL.loadImage(obj.URL, function(img) {
13594						//Trigger the onAfterLoad callback
13595						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13596						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13597
13598						var width = (img) ? img.width : 400,
13599							height = (img) ? img.height : 200;
13600
13601						holder.data({
13602							naturalWidth: width,
13603							naturalHeight: height
13604						});
13605
13606						$('div.ilightbox-container', holder).empty().append((img) ? '<img src="' + obj.URL + '" class="ilightbox-image" />' : '<span class="ilightbox-alert">' + opts.errors.loadImage + '</span>');
13607
13608						//Trigger the onRender callback
13609						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13610						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13611
13612						iL.configureHolder(obj, opt, holder);
13613					});
13614
13615					break;
13616
13617				case 'video':
13618					holder.data({
13619						naturalWidth: obj.options.width,
13620						naturalHeight: obj.options.height
13621					});
13622
13623					if (opt === 'current') {
13624						iL.addContent(holder, obj);
13625
13626						//Trigger the onRender callback
13627						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13628						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13629					} else {
13630						$('div.ilightbox-container', holder).empty();
13631					}
13632
13633					iL.configureHolder(obj, opt, holder);
13634
13635					break;
13636
13637				case 'iframe':
13638					//iL.showLoader();
13639					holder.data({
13640						naturalWidth: obj.options.width,
13641						naturalHeight: obj.options.height
13642					});
13643
13644					iL.configureHolder(obj, opt, holder);
13645
13646					if (opt === 'current') {
13647						var el = iL.addContent(holder, obj);
13648
13649						//Trigger the onRender callback
13650						if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13651						if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13652
13653						//Trigger the onBeforeLoad callback
13654						if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
13655						if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
13656
13657						el.bind('load', function() {
13658							//Trigger the onAfterLoad callback
13659							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13660							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13661
13662							//iL.hideLoader();
13663							el.unbind('load');
13664						});
13665					} else {
13666						$('div.ilightbox-container', holder).empty();
13667					}
13668
13669					break;
13670
13671				case 'inline':
13672					var el = $(obj.URL),
13673						content = iL.addContent(holder, obj),
13674						images = findImageInElement(holder);
13675
13676					holder.data({
13677						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
13678						naturalHeight: (iL.items[item].options.height || el.outerHeight())
13679					});
13680					content.children().eq(0).show();
13681
13682					//Trigger the onRender callback
13683					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13684					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13685
13686					//Trigger the onBeforeLoad callback
13687					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
13688					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
13689
13690					iL.loadImage(images, function() {
13691						//Trigger the onAfterLoad callback
13692						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13693						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13694
13695						iL.configureHolder(obj, opt, holder);
13696					});
13697
13698					break;
13699
13700				case 'flash':
13701					var el = iL.addContent(holder, obj);
13702
13703					holder.data({
13704						naturalWidth: (iL.items[item].options.width || el.outerWidth()),
13705						naturalHeight: (iL.items[item].options.height || el.outerHeight())
13706					});
13707
13708					//Trigger the onRender callback
13709					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13710					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13711
13712					iL.configureHolder(obj, opt, holder);
13713
13714					break;
13715
13716				case 'ajax':
13717					var ajax = obj.options.ajax || {};
13718					//Trigger the onBeforeLoad callback
13719					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
13720					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
13721
13722					iL.showLoader();
13723					$.ajax({
13724						url: obj.URL || opts.ajaxSetup.url,
13725						data: ajax.data || null,
13726						dataType: ajax.dataType || "html",
13727						type: ajax.type || opts.ajaxSetup.type,
13728						cache: ajax.cache || opts.ajaxSetup.cache,
13729						crossDomain: ajax.crossDomain || opts.ajaxSetup.crossDomain,
13730						global: ajax.global || opts.ajaxSetup.global,
13731						ifModified: ajax.ifModified || opts.ajaxSetup.ifModified,
13732						username: ajax.username || opts.ajaxSetup.username,
13733						password: ajax.password || opts.ajaxSetup.password,
13734						beforeSend: ajax.beforeSend || opts.ajaxSetup.beforeSend,
13735						complete: ajax.complete || opts.ajaxSetup.complete,
13736						success: function(data, textStatus, jqXHR) {
13737							iL.hideLoader();
13738
13739							var el = $(data),
13740								container = $('div.ilightbox-container', holder),
13741								elWidth = iL.items[item].options.width || parseInt(el[0].getAttribute('width')),
13742								elHeight = iL.items[item].options.height || parseInt(el[0].getAttribute('height')),
13743								css = (el[0].getAttribute('width') && el[0].getAttribute('height')) ? {
13744									'overflow': 'hidden'
13745								} : {};
13746
13747							container.empty().append($('<div class="ilightbox-wrapper"></div>').css(css).html(el));
13748							holder.show().data({
13749								naturalWidth: (elWidth || container.outerWidth()),
13750								naturalHeight: (elHeight || container.outerHeight())
13751							}).hide();
13752
13753							//Trigger the onRender callback
13754							if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13755							if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13756
13757							var images = findImageInElement(holder);
13758							iL.loadImage(images, function() {
13759								//Trigger the onAfterLoad callback
13760								if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13761								if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13762
13763								iL.configureHolder(obj, opt, holder);
13764							});
13765
13766							opts.ajaxSetup.success(data, textStatus, jqXHR);
13767							if (typeof ajax.success == 'function') ajax.success(data, textStatus, jqXHR);
13768						},
13769						error: function(jqXHR, textStatus, errorThrown) {
13770							//Trigger the onAfterLoad callback
13771							if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13772							if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13773
13774							iL.hideLoader();
13775							$('div.ilightbox-container', holder).empty().append('<span class="ilightbox-alert">' + opts.errors.loadContents + '</span>');
13776							iL.configureHolder(obj, opt, holder);
13777
13778							opts.ajaxSetup.error(jqXHR, textStatus, errorThrown);
13779							if (typeof ajax.error == 'function') ajax.error(jqXHR, textStatus, errorThrown);
13780						}
13781					});
13782
13783					break;
13784
13785				case 'html':
13786					var object = obj.URL,
13787						el
13788					container = $('div.ilightbox-container', holder);
13789
13790					if (object[0].nodeName) el = object.clone();
13791					else {
13792						var dom = $(object);
13793						if (dom.selector) el = $('<div>' + dom + '</div>');
13794						else el = dom;
13795					}
13796
13797					var elWidth = iL.items[item].options.width || parseInt(el.attr('width')),
13798						elHeight = iL.items[item].options.height || parseInt(el.attr('height'));
13799
13800					iL.addContent(holder, obj);
13801
13802					el.appendTo(document.documentElement).hide();
13803
13804					//Trigger the onRender callback
13805					if (typeof opts.callback.onRender == 'function') opts.callback.onRender.call(iL, iL.ui, item);
13806					if (typeof obj.options.onRender == 'function') obj.options.onRender.call(iL, api);
13807
13808					var images = findImageInElement(holder);
13809
13810					//Trigger the onBeforeLoad callback
13811					if (typeof opts.callback.onBeforeLoad == 'function') opts.callback.onBeforeLoad.call(iL, iL.ui, item);
13812					if (typeof obj.options.onBeforeLoad == 'function') obj.options.onBeforeLoad.call(iL, api);
13813
13814					iL.loadImage(images, function() {
13815						//Trigger the onAfterLoad callback
13816						if (typeof opts.callback.onAfterLoad == 'function') opts.callback.onAfterLoad.call(iL, iL.ui, item);
13817						if (typeof obj.options.onAfterLoad == 'function') obj.options.onAfterLoad.call(iL, api);
13818
13819						holder.show().data({
13820							naturalWidth: (elWidth || container.outerWidth()),
13821							naturalHeight: (elHeight || container.outerHeight())
13822						}).hide();
13823						el.remove();
13824
13825						iL.configureHolder(obj, opt, holder);
13826					});
13827
13828					break;
13829			}
13830		},
13831
13832		configureHolder: function(obj, opt, holder) {
13833			var iL = this,
13834				vars = iL.vars,
13835				opts = iL.options;
13836
13837			if (opt != "current")(opt == "next") ? holder.addClass('ilightbox-next') : holder.addClass('ilightbox-prev');
13838
13839			if (opt == "current")
13840				var item = vars.current;
13841			else if (opt == "next")
13842				var opacity = opts.styles.nextOpacity,
13843					item = vars.next;
13844			else
13845				var opacity = opts.styles.prevOpacity,
13846					item = vars.prev;
13847
13848			var api = {
13849				element: holder,
13850				position: item
13851			};
13852
13853			iL.items[item].options.width = iL.items[item].options.width || 0,
13854			iL.items[item].options.height = iL.items[item].options.height || 0;
13855
13856			if (opt == "current") {
13857				if (opts.show.effect) holder.css(transform, gpuAcceleration).fadeIn(obj.speed, function() {
13858					holder.css(transform, '');
13859					if (obj.caption) {
13860						iL.setCaption(obj, holder);
13861						var caption = $('div.ilightbox-caption', holder),
13862							percent = parseInt((caption.outerHeight() / holder.outerHeight()) * 100);
13863						if (opts.caption.start & percent <= 50) caption.fadeIn(opts.effects.fade
13863Speed);
13864					}
13865
13866					var social = obj.options.social;
13867					if (social) {
13868						iL.setSocial(social, obj.URL, holder);
13869						if (opts.social.start) $('div.ilightbox-social', holder).fadeIn(opts.effects.fadeSpeed);
13870					}
13871
13872					//Generate thumbnails
13873					iL.generateThumbnails();
13874
13875					//Trigger the onShow callback
13876					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
13877					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
13878				});
13879				else {
13880					holder.show();
13881
13882					//Generate thumbnails
13883					iL.generateThumbnails();
13884
13885					//Trigger the onShow callback
13886					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
13887					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
13888				}
13889			} else {
13890				if (opts.show.effect) holder.fadeTo(obj.speed, opacity, function() {
13891					if (opt == "next") vars.nextLock = false;
13892					else vars.prevLock = false;
13893
13894					//Generate thumbnails
13895					iL.generateThumbnails();
13896
13897					//Trigger the onShow callback
13898					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
13899					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
13900				});
13901				else {
13902					holder.css({
13903						opacity: opacity
13904					}).show();
13905					if (opt == "next") vars.nextLock = false;
13906					else vars.prevLock = false;
13907
13908					//Generate thumbnails
13909					iL.generateThumbnails();
13910
13911					//Trigger the onShow callback
13912					if (typeof opts.callback.onShow == 'function') opts.callback.onShow.call(iL, iL.ui, item);
13913					if (typeof obj.options.onShow == 'function') obj.options.onShow.call(iL, api);
13914				}
13915			}
13916
13917			setTimeout(function() {
13918				iL.repositionPhoto();
13919			}, 0);
13920		},
13921
13922		generateBoxes: function() {
13923			var iL = this,
13924				vars = iL.vars,
13925				opts = iL.options;
13926
13927			if (opts.infinite && vars.total >= 3) {
13928				if (vars.current == vars.total - 1) vars.next = 0;
13929				if (vars.current == 0) vars.prev = vars.total - 1;
13930			} else opts.infinite = false;
13931
13932			//UNCODE addition
13933			if ( typeof iL.items[vars.current] == 'undefined' )
13934				vars.current = 0;
13935
13936			iL.loadContent(iL.items[vars.current], 'current', opts.show.speed);
13937
13938			if (iL.items[vars.next]) iL.loadContent(iL.items[vars.next], 'next', opts.show.speed);
13939			if (iL.items[vars.prev]) iL.loadContent(iL.items[vars.prev], 'prev', opts.show.speed);
13940		},
13941
13942		generateThumbnails: function() {
13943			var iL = this,
13944				vars = iL.vars,
13945				opts = iL.options,
13946				timeOut = null;
13947
13948			if (vars.thumbs && !iL.vars.dontGenerateThumbs) {
13949				var thumbnails = vars.thumbnails,
13950					container = $('div.ilightbox-thumbnails-container', thumbnails),
13951					grid = $('div.ilightbox-thumbnails-grid', container),
13952					i = 0;
13953
13954				grid.removeAttr('style').empty();
13955
13956				$.each(iL.items, function(key, val) {
13957					var isActive = (vars.current == key) ? 'ilightbox-active' : '',
13958						opacity = (vars.current == key) ? opts.thumbnails.activeOpacity : opts.thumbnails.normalOpacity,
13959						thumb = val.options.thumbnail,
13960						thumbnail = $('<div class="ilightbox-thumbnail"></div>'),
13961						icon = $('<div class="ilightbox-thumbnail-icon"></div>');
13962
13963					thumbnail.css({
13964						opacity: 0
13965					}).addClass(isActive);
13966
13967					if ((val.type == "video" || val.type == "flash") && typeof val.options.icon == 'undefined') {
13968						icon.addClass('ilightbox-thumbnail-video');
13969						thumbnail.append(icon);
13970					} else if (val.options.icon) {
13971						icon.addClass('ilightbox-thumbnail-' + val.options.icon);
13972						thumbnail.append(icon);
13973					}
13974
13975					if (thumb) iL.loadImage(thumb, function(img) {
13976						i++;
13977						if (img) thumbnail.data({
13978							naturalWidth: img.width,
13979							naturalHeight: img.height
13980						}).append('<img src="' + thumb + '" border="0" />');
13981						else thumbnail.data({
13982							naturalWidth: opts.thumbnails.maxWidth,
13983							naturalHeight: opts.thumbnails.maxHeight
13984						});
13985
13986						clearTimeout(timeOut);
13987						timeOut = setTimeout(function() {
13988							iL.positionThumbnails(thumbnails, container, grid);
13989						}, 20);
13990						setTimeout(function() {
13991							thumbnail.fadeTo(opts.effects.loadedFadeSpeed, opacity);
13992						}, i * 20);
13993					});
13994
13995					grid.append(thumbnail);
13996				});
13997				iL.vars.dontGenerateThumbs = true;
13998			}
13999		},
14000
14001		positionThumbnails: function(thumbnails, container, grid) {
14002			var iL = this,
14003				vars = iL.vars,
14004				opts = iL.options,
14005				viewport = getViewport(),
14006				path = opts.path.toLowerCase();
14007
14008			if (!thumbnails) thumbnails = vars.thumbnails;
14009			if (!container) container = $('div.ilightbox-thumbnails-container', thumbnails);
14010			if (!grid) grid = $('div.ilightbox-thumbnails-grid', container);
14011
14012			var thumbs = $('.ilightbox-thumbnail', grid),
14013				widthAvail = (path == 'horizontal') ? viewport.width - opts.styles.pageOffsetX : thumbs.eq(0).outerWidth() - opts.styles.pageOffsetX,
14014				heightAvail = (path == 'horizontal') ? thumbs.eq(0).outerHeight() - opts.styles.pageOffsetY : viewport.height - opts.styles.pageOffsetY,
14015				gridWidth = (path == 'horizontal') ? 0 : widthAvail,
14016				gridHeight = (path == 'horizontal') ? heightAvail : 0,
14017				active = $('.ilightbox-active', grid),
14018				gridCss = {},
14019				css = {};
14020
14021			if (arguments.length < 3) {
14022				thumbs.css({
14023					opacity: opts.thumbnails.normalOpacity
14024				});
14025				active.css({
14026					opacity: opts.thumbnails.activeOpacity
14027				});
14028			}
14029
14030			thumbs.each(function(i) {
14031				var t = $(this),
14032					data = t.data(),
14033					width = (path == 'horizontal') ? 0 : opts.thumbnails.maxWidth;
14034				height = (path == 'horizontal') ? opts.thumbnails.maxHeight : 0;
14035				dims = iL.getNewDimenstions(width, height, data.naturalWidth, data.naturalHeight, true);
14036
14037				t.css({
14038					width: dims.width,
14039					height: dims.height
14040				});
14041				if (path == 'horizontal') t.css({
14042					'float': 'left'
14043				});
14044
14045				(path == 'horizontal') ? (
14046					gridWidth += t.outerWidth()
14047				) : (
14048					gridHeight += t.outerHeight()
14049				);
14050			});
14051
14052			gridCss = {
14053				width: gridWidth,
14054				height: gridHeight
14055			};
14056
14057			grid.css(gridCss);
14058
14059			gridCss = {};
14060
14061			var gridOffset = grid.offset(),
14062				activeOffset = (active.length) ? active.offset() : {
14063					top: parseInt(heightAvail / 2),
14064					left: parseInt(widthAvail / 2)
14065				};
14066
14067			gridOffset.top = (gridOffset.top - $doc.scrollTop()),
14068				gridOffset.left = (gridOffset.left - $doc.scrollLeft()),
14069				activeOffset.top = (activeOffset.top - gridOffset.top - $doc.scrollTop()),
14070				activeOffset.left = (activeOffset.left - gridOffset.left - $doc.scrollLeft());
14071
14072			(path == 'horizontal') ? (
14073				gridCss.top = 0,
14074				gridCss.left = parseInt((widthAvail / 2) - activeOffset.left - (active.outerWidth() / 2))
14075			) : (
14076				gridCss.top = parseInt(((heightAvail / 2) - activeOffset.top - (active.outerHeight() / 2))),
14077				gridCss.left = 0
14078			);
14079
14080			if (arguments.length < 3) grid.stop().animate(gridCss, opts.effects.repositionSpeed, 'easeOutCirc');
14081			else grid.css(gridCss);
14082		},
14083
14084		loadImage: function(image, callback) {
14085			if (!$.isArray(image)) image = [image];
14086
14087			var iL = this,
14088				length = image.length;
14089
14090			if (length > 0) {
14091				iL.showLoader();
14092				$.each(image, function(index, value) {
14093					var img = new Image();
14094					img.onload = function() {
14095						length -= 1;
14096						if (length == 0) {
14097							iL.hideLoader();
14098							callback(img);
14099						}
14100					};
14101					img.onerror = img.onabort = function() {
14102						length -= 1;
14103						if (length == 0) {
14104							iL.hideLoader();
14105							callback(false);
14106						}
14107					};
14108					img.src = image[index];
14109				});
14110			} else callback(false);
14111		},
14112
14113		patchItemsEvents: function() {
14114			var iL = this,
14115				vars = iL.vars,
14116				clickEvent = ishybrid ? "itap.iL click.iL" : supportTouch ? "itap.iL" : "click.iL",
14117				vEvent = ishybrid ? "click.iL itap.iL" : supportTouch ? "click.iL" : "itap.iL";
14118
14119			if (iL.context && iL.selector) {
14120				var $items = $(iL.selector, iL.context);
14121
14122				$(iL.context).on(clickEvent, iL.selector, function() {
14123					var $this = $(this),
14124						//UNCODE addition
14125						key = typeof $(this).data('lb-index') !== '' && $(this).closest('.owl-item').length ? $(this).data('lb-index') : $items.index($this);
14126					if (UNCODE.isMobile) {
14127						var isCarousel = $this.closest('.owl-carousel');
14128						if (isCarousel.length) {
14129							if (isCarousel.hasClass('owl-translating')) return false;
14130						}
14131					}
14132
14133					vars.current = key;
14134					vars.next = iL.items[key + 1] ? key + 1 : null;
14135					vars.prev = iL.items[key - 1] ? key - 1 : null;
14136
14137					//UNCODE addition
14138					if ( vars.BODY.hasClass('fp-slide-scrolling') )
14139						return false;
14140
14141					iL.addContents();
14142					iL.patchEvents();
14143
14144					return false;
14145				}).on(vEvent, iL.selector, function() {
14146					return false;
14147				});
14148			} else
14149				$.each(iL.itemsObject, function(key, val) {
14150					val.on(clickEvent, function() {
14151						vars.current = key;
14152						vars.next = iL.items[key + 1] ? key + 1 : null;
14153						vars.prev = iL.items[key - 1] ? key - 1 : null;
14154
14155						iL.addContents();
14156						iL.patchEvents();
14157
14158						return false;
14159					}).on(vEvent, function() {
14160						return false;
14161					});
14162				});
14163		},
14164
14165		dispatchItemsEvents: function() {
14166			var iL = this,
14167				vars = iL.vars,
14168				opts = iL.options;
14169
14170			if (iL.context && iL.selector)
14171				$(iL.context).off('.iL', iL.selector);
14172			else
14173				$.each(iL.itemsObject, function(key, val) {
14174					val.off('.iL');
14175				});
14176		},
14177
14178		refresh: function() {
14179			var iL = this;
14180
14181			iL.dispatchItemsEvents();
14182			iL.attachItems();
14183			iL.normalizeItems();
14184			iL.patchItemsEvents();
14185		},
14186
14187		patchEvents: function() {
14188			var iL = this,
14189				vars = iL.vars,
14190				opts = iL.options,
14191				path = opts.path.toLowerCase(),
14192				holders = $('.ilightbox-holder'),
14193				fullscreenEvent = fullScreenApi.fullScreenEventName + '.iLightBox',
14194				durationThreshold = 1000,
14195				horizontalDistanceThreshold =
14196				verticalDistanceThreshold = 100,
14197				buttonsArray = [vars.nextButton[0], vars.prevButton[0], vars.nextButton[0].firstChild, vars.prevButton[0].firstChild];
14198
14199			$win.bind('resize.iLightBox', function() {
14200				var viewport = getViewport();
14201
14202				if (opts.mobileOptimizer && !opts.innerToolbar) vars.isMobile = viewport.width <= vars.mobileMaxWidth;
14203				vars.BODY[vars.isMobile ? 'addClass' : 'removeClass']('isMobile');
14204
14205				iL.repositionPhoto(null);
14206				if (supportTouch) {
14207					clearTimeout(vars.setTime);
14208					vars.setTime = setTimeout(function() {
14209						var scrollTop = getScrollXY().y;
14210						window.scrollTo(0, scrollTop - 30);
14211						window.scrollTo(0, scrollTop + 30);
14212						window.scrollTo(0, scrollTop);
14213					}, 2000);
14214				}
14215				if (vars.thumbs) iL.positionThumbnails();
14216			}).bind('keydown.iLightBox', function(event) {
14217				if (opts.controls.keyboard) {
14218					switch (event.keyCode) {
14219						case 13:
14220							if (event.shiftKey && opts.keyboard.shift_enter) iL.fullScreenAction();
14221							break;
14222						case 27:
14223							if (opts.keyboard.esc) iL.closeAction();
14224							break;
14225						case 37:
14226							if (opts.keyboard.left && !vars.lockKey) iL.moveTo('prev');
14227							break;
14228						case 38:
14229							if (opts.keyboard.up && !vars.lockKey) iL.moveTo('prev');
14230							break;
14231						case 39:
14232							if (opts.keyboard.right && !vars.lockKey) iL.moveTo('next');
14233							break;
14234						case 40:
14235							if (opts.keyboard.down && !vars.lockKey) iL.moveTo('next');
14236							break;
14237					}
14238				}
14239			});
14240
14241			if (fullScreenApi.supportsFullScreen) $win.bind(fullscreenEvent, function() {
14242				iL.doFullscreen();
14243			});
14244
14245			var holderEventsArr = [opts.caption.show + '.iLightBox', opts.caption.hide + '.iLightBox', opts.social.show + '.iLightBox', opts.social.hide + '.iLightBox'].filter(function(e, i, arr) {
14246					return arr.lastIndexOf(e) === i;
14247				}),
14248				holderEvents = "";
14249
14250			$.each(holderEventsArr, function(key, val) {
14251				if (key != 0) holderEvents += ' ';
14252				holderEvents += val;
14253			});
14254
14255			$doc.on(clickEvent, '.ilightbox-overlay', function() {
14256				if (opts.overlay.blur) iL.closeAction();
14257			}).on(clickEvent, '.ilightbox-next, .ilightbox-next-button', function() {
14258				iL.moveTo('next');
14259			}).on(clickEvent, '.ilightbox-prev, .ilightbox-prev-button', function() {
14260				iL.moveTo('prev');
14261			}).on(clickEvent, '.ilightbox-thumbnail', function() {
14262				var t = $(this),
14263					thumbs = $('.ilightbox-thumbnail', vars.thumbnails),
14264					index = thumbs.index(t);
14265
14266				if (index != vars.current) iL.goTo(index);
14267			}).on(holderEvents, '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
14268				var caption = $('div.ilightbox-caption', vars.holder),
14269					social = $('div.ilightbox-social', vars.holder),
14270					fadeSpeed = opts.effects.fadeSpeed;
14271
14272				if (vars.nextLock || vars.prevLock) {
14273					if (e.type == opts.caption.show && !caption.is(':visible')) caption.fadeIn(fadeSpeed);
14274					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.fadeOut(fadeSpeed);
14275
14276					if (e.type == opts.social.show && !social.is(':visible')) social.fadeIn(fadeSpeed);
14277					else if (e.type == opts.social.hide && social.is(':visible')) social.fadeOut(fadeSpeed);
14278				} else {
14279					if (e.type == opts.caption.show && !caption.is(':visible')) caption.stop().fadeIn(fadeSpeed);
14280					else if (e.type == opts.caption.hide && caption.is(':visible')) caption.stop().fadeOut(fadeSpeed);
14281
14282					if (e.type == opts.social.show && !social.is(':visible')) social.stop().fadeIn(fadeSpeed);
14283					else if (e.type == opts.social.hide && social.is(':visible')) social.stop().fadeOut(fadeSpeed);
14284				}
14285			}).on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-wrapper', function(e) {
14286				if (e.type == 'mouseenter') vars.lockWheel = true;
14287				else vars.lockWheel = false;
14288			}).on(clickEvent, '.ilightbox-toolbar a.ilightbox-close, .ilightbox-toolbar a.ilightbox-fullscreen, .ilightbox-toolbar a.ilightbox-play, .ilightbox-toolbar a.ilightbox-pause', function() {
14289				var t = $(this);
14290
14291				if (t.hasClass('ilightbox-fullscreen')) iL.fullScreenAction();
14292				else if (t.hasClass('ilightbox-play')) {
14293					iL.resume();
14294					t.addClass('ilightbox-pause').removeClass('ilightbox-play');
14295				} else if (t.hasClass('ilightbox-pause')) {
14296					iL.pause();
14297					t.addClass('ilightbox-play').removeClass('ilightbox-pause');
14298				} else iL.closeAction();
14299			}).on(touchMoveEvent, '.ilightbox-overlay, .ilightbox-thumbnails-container', function(e) {
14300				// prevent scrolling
14301				e.preventDefault();
14302			});
14303
14304			function mouseMoveHandler(e) {
14305				if (!vars.isMobile) {
14306					if (!vars.mouseID) {
14307						vars.hideableElements.show();
14308					}
14309
14310					vars.mouseID = clearTimeout(vars.mouseID);
14311
14312					if (buttonsArray.indexOf(e.target) === -1)
14313						vars.mouseID = setTimeout(function() {
14314							vars.hideableElements.hide();
14315							vars.mouseID = clearTimeout(vars.mouseID);
14316						}, 3000);
14317				}
14318			}
14319
14320			if (opts.controls.arrows && !supportTouch) $doc.on('mousemove.iLightBox', mouseMoveHandler);
14321
14322			if (opts.controls.slideshow && opts.slideshow.pauseOnHover) $doc.on('mouseenter.iLightBox mouseleave.iLightBox', '.ilightbox-holder:not(.ilightbox-next, .ilightbox-prev)', function(e) {
14323				if (e.type == 'mouseenter' && vars.cycleID) iL.pause();
14324				else if (e.type == 'mouseleave' && vars.isPaused) iL.resume();
14325			});
14326
14327			var switchers = $('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails'),
14328				delay = false;
14329
14330			if (opts.controls.mousewheel) switchers.on('mousewheel.iLightBox', function(event, delta) {
14331				event.preventDefault();
14332				if (delay) return;
14333				delay = true;
14334				if (!vars.lockWheel) {
14335					event.preventDefault();
14336					if (delta < 0) {
14337						iL.moveTo('next');
14338					} else if (delta > 0) {
14339						iL.moveTo('prev');
14340					}
14341				}
14342				setTimeout(function(){
14343					delay = false;
14344				}, 2000);
14345			});
14346
14347			if (opts.controls.swipe) holders.on(touchStartEvent, function(event) {
14348				if (vars.nextLock || vars.prevLock || vars.total == 1 || vars.lockSwipe) return;
14349
14350				vars.BODY.addClass('ilightbox-closedhand');
14351
14352				var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event,
14353					scrollTop = $doc.scrollTop(),
14354					scrollLeft = $doc.scrollLeft(),
14355					offsets = [
14356						holders.eq(0).offset(),
14357						holders.eq(1).offset(),
14358						holders.eq(2).offset()
14359					],
14360					offSet = [{
14361						top: offsets[0].top - scrollTop,
14362						left: offsets[0].left - scrollLeft
14363					}, {
14364						top: offsets[1].top - scrollTop,
14365						left: offsets[1].left - scrollLeft
14366					}, {
14367						top: offsets[2].top - scrollTop,
14368						left: offsets[2].left - scrollLeft
14369					}],
14370					start = {
14371						time: (new Date()).getTime(),
14372						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
14373					},
14374					stop;
14375
14376				function moveEachHandler(i) {
14377					var t = $(this),
14378						offset = offSet[i],
14379						scroll = [(start.coords[0] - stop.coords[0]), (start.coords[1] - stop.coords[1])];
14380
14381					t[0].style[path == "horizontal" ? 'left' : 'top'] = (path == "horizontal" ? offset.left - scroll[0] : offset.top - scroll[1]) + 'px';
14382				}
14383
14384				function moveHandler(event) {
14385
14386					if (!start) return;
14387
14388					var data = event.originalEvent.touches ? event.originalEvent.touches[0] : event;
14389
14390					stop = {
14391						time: (new Date()).getTime(),
14392						coords: [data.pageX - scrollLeft, data.pageY - scrollTop]
14393					};
14394
14395					holders.each(moveEachHandler);
14396
14397					// prevent scrolling
14398					event.preventDefault();
14399				}
14400
14401				function repositionHolders() {
14402					holders.each(function() {
14403						var t = $(this),
14404							offset = t.data('offset') || {
14405								top: t.offset().top - scrollTop,
14406								left: t.offset().left - scrollLeft
14407							},
14408							top = offset.top,
14409							left = offset.left;
14410
14411						t.css(transform, gpuAcceleration).stop().animate({
14412							top: top,
14413							left: left
14414						}, 500, 'easeOutCirc', function() {
14415							t.css(transform, '');
14416						});
14417					});
14418				}
14419
14420				holders.bind(touchMoveEvent, moveHandler);
14421				$doc.one(touchStopEvent, function(event) {
14422					holders.unbind(touchMoveEvent, moveHandler);
14423
14424					vars.BODY.removeClass('ilightbox-closedhand');
14425
14426					if (start && stop) {
14427						if (path == "horizontal" && stop.time - start.time < durationThreshold && abs(start.coords[0] - stop.coords[0]) > horizontalDistanceThreshold && abs(start.coords[1] - stop.coords[1]) < verticalDistanceThreshold) {
14428							if (start.coords[0] > stop.coords[0]) {
14429								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
14430								else {
14431									vars.isSwipe = true;
14432									iL.moveTo('next');
14433								}
14434							} else {
14435								if (vars.current == 0 && !opts.infinite) repositionHolders();
14436								else {
14437									vars.isSwipe = true;
14438									iL.moveTo('prev');
14439								}
14440							}
14441						} 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) {
14442							if (start.coords[1] > stop.coords[1]) {
14443								if (vars.current == vars.total - 1 && !opts.infinite) repositionHolders();
14444								else {
14445									vars.isSwipe = true;
14446									iL.moveTo('next');
14447								}
14448							} else {
14449								if (vars.current == 0 && !opts.infinite) repositionHolders();
14450								else {
14451									vars.isSwipe = true;
14452									iL.moveTo('prev');
14453								}
14454							}
14455						} else repositionHolders();
14456					}
14457					start = stop = undefined;
14458				});
14459			});
14460
14461		},
14462
14463		goTo: function(index) {
14464			var iL = this,
14465				vars = iL.vars,
14466				opts = iL.options,
14467				diff = (index - vars.current);
14468
14469			if (opts.infinite) {
14470				if (index == vars.total - 1 && vars.current == 0) diff = -1;
14471				if (vars.current == vars.total - 1 && index == 0) diff = 1;
14472			}
14473
14474			if (diff == 1) iL.moveTo('next');
14475			else if (diff == -1) iL.moveTo('prev');
14476			else {
14477
14478				if (vars.nextLock || vars.prevLock) return false;
14479
14480				//Trigger the onBeforeChange callback
14481				if (typeof opts.callback.onBeforeChange == 'function') opts.callback.onBeforeChange.call(iL, iL.ui);
14482
14483				if (opts.linkId) {
14484					vars.hashLock = true;
14485					window.location.hash = opts.linkId + '/' + index;
14486				}
14487
14488				if (iL.items[index]) {
14489					if (!iL.items[index].options.mousewheel) vars.lockWheel = true;
14490					else iL.vars.lockWheel = false;
14491
14492					if (!iL.items[index].options.swipe) vars.lockSwipe = true;
14493					else vars.lockSwipe = false;
14494				}
14495
14496				$.each([vars.holder, vars.nextPhoto, vars.prevPhoto], function(key, val) {
14497					val.css(transform, gpuAcceleration).fadeOut(opts.effects.loadedFadeSpeed);
14498				});
14499
14500				vars.current = index;
14501				vars.next = index + 1;
14502				vars.prev = index - 1;
14503
14504				iL.createUI();
14505
14506				setTimeout(function() {
14507					iL.generateBoxes();
14508				}, opts.effects.loadedFadeSpeed + 50);
14509
14510				$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(index).addClass('ilightbox-active');
14511				iL.positionThumbnails();
14512
14513				if (opts.linkId) setTimeout(function() {
14514					vars.hashLock = false;
14515				}, 55);
14516
14517				// Configure arrow buttons
14518				if (!opts.infinite) {
14519					vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
14520
14521					if (vars.current == 0) {
14522						vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
14523					}
14524					if (vars.current >= vars.total - 1) {
14525						vars.nextButton.add(vars.innerNextButton).addClass('disabled');
14526					}
14527				}
14528
14529				// Reset next cycle timeout
14530				iL.resetCycle();
14531
14532				//Trigger the onAfterChange callback
14533				if (typeof opts.callback.onAfterChange == 'function') opts.callback.onAfterChange.call(iL, iL.ui);
14534			}
14535		},
14536
14537		moveTo: function(side) {
14538			var iL = this,
14539				vars = iL.vars,
14540				opts = iL.options,
14541				path = opts.path.toLowerCase(),
14542				viewport = getViewport(),
14543				switchSpeed = opts.effects.switchSpeed;
14544
14545			if (vars.nextLock || vars.prevLock) return false;
14546			else {
14547
14548				var item = (side == "next") ? vars.next : vars.prev;
14549
14550				if (opts.linkId) {
14551					vars.hashLock = true;
14552					window.location.hash = opts.linkId + '/' + item;
14553				}
14554
14555				if (side == "next") {
14556					if (!iL.items[item]) return false;
14557					var firstHolder = vars.nextPhoto,
14558						secondHolder = vars.holder,
14559						lastHolder = vars.prevPhoto,
14560						firstClass = 'ilightbox-prev',
14561						secondClass = 'ilightbox-next';
14562				} else if (side == "prev") {
14563					if (!iL.items[item]) return false;
14564					var firstHolder = vars.prevPhoto,
14565						secondHolder = vars.holder,
14566						lastHolder = vars.nextPhoto,
14567						firstClass = 'ilightbox-next',
14568						secondClass = 'ilightbox-prev';
14569				}
14570
14571				//Trigger the onBeforeChange callback
14572				if (typeof opts.callback.onBeforeChange == 'function')
14573					opts.callback.onBeforeChange.call(iL, iL.ui);
14574
14575				(side == "next") ? vars.nextLock = true: vars.prevLock = true;
14576
14577				var captionFirst = $('div.ilightbox-caption', secondHolder),
14578					socialFirst = $('div.ilightbox-social', secondHolder);
14579
14580				if (captionFirst.length)
14581					captionFirst.stop().fadeOut(switchSpeed, function() {
14582						$(this).remove();
14583					});
14584				if (socialFirst.length)
14585					socialFirst.stop().fadeOut(switchSpeed, function() {
14586						$(this).remove();
14587					});
14588
14589				if (iL.items[item].caption) {
14590					iL.setCaption(iL.items[item], firstHolder);
14591					var caption = $('div.ilightbox-caption', firstHolder),
14592						percent = parseInt((caption.outerHeight() / firstHolder.outerHeight()) * 100);
14593					if (opts.caption.start && percent <= 50) caption.fadeIn(switchSpeed);
14594				}
14595
14596				var social = iL.items[item].options.social;
14597				if (social) {
14598					iL.setSocial(social, iL.items[item].URL, firstHolder);
14599					if (opts.social.start) $('div.ilightbox-social', firstHolder).fadeIn(opts.effects.fadeSpeed);
14600				}
14601
14602				$.each([firstHolder, secondHolder, lastHolder], function(key, val) {
14603					val.removeClass('ilightbox-next ilightbox-prev');
14604				});
14605
14606				var firstOffset = firstHolder.data('offset'),
14607					winW = (viewport.width - (opts.styles.pageOffsetX)),
14608					winH = (viewport.height - (opts.styles.pageOffsetY)),
14609					width = firstOffset.newDims.width,
14610					height = firstOffset.newDims.height,
14611					thumbsOffset = firstOffset.thumbsOffset,
14612					diff = firstOffset.diff,
14613					top = parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)),
14614					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
14615
14616				var secondOffset = secondHolder.data('offset'),
14617					object = secondOffset.object;
14618
14619				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
14620					var objRatio = width / height;
14621					height = height - vars.captionHeight;
14622					width = height * objRatio;
14623					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top,
14624					left = parseInt((winW / 2) - (width / 2) - diff.W - (thumbsOffset.W / 2));
14625				}*/
14626
14627				firstHolder.show().css(transform, gpuAcceleration).animate({
14628					top: top,
14629					left: left,
14630					opacity: 1
14631				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
14632					firstHolder.css(transform, '');
14633				});
14634
14635				$('div.ilightbox-container', firstHolder).animate({
14636					width: width,
14637					height: height
14638				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
14639
14640				diff = secondOffset.diff;
14641
14642				width = secondOffset.newDims.width,
14643					height = secondOffset.newDims.height;
14644
14645				width = parseInt(width * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
14646					height = parseInt(height * opts.styles[side == 'next' ? 'prevScale' : 'nextScale']),
14647					top = (path == 'horizontal') ? parseInt((winH / 2) - object.offsetY - (height / 2) - diff.H - (thumbsOffset.H / 2)) : parseInt(winH - object.offsetX - diff.H - (thumbsOffset.H / 2));
14648
14649				if (side == 'prev')
14650					left = (path == 'horizontal') ? parseInt(winW - object.offsetX - diff.W - (thumbsOffset.W / 2)) : parseInt((winW / 2) - (width / 2) - diff.W - object.offsetY - (thumbsOffset.W / 2));
14651				else {
14652					top = (path == 'horizontal') ? top : parseInt(object.offsetX - diff.H - height - (thumbsOffset.H / 2)),
14653					left = (path == 'horizontal') ? parseInt(object.offsetX - diff.W - width - (thumbsOffset.W / 2)) : parseInt((winW / 2) - object.offsetY - (width / 2) - diff.W - (thumbsOffset.W / 2));
14654				}
14655
14656				/*if (object.item.caption && !isNaN(width) && !isNaN(height) && UNCODE.wwidth > UNCODE.mediaQuery) {
14657					var objRatio = width / height;
14658					height = height - vars.captionHeight;
14659					width = height * objRatio;
14660					top = path == 'horizontal' ? parseInt((winH / 2) - (height / 2) - diff.H - (thumbsOffset.H / 2)) : top;
14661				}*/
14662
14663				$('div.ilightbox-container', secondHolder).animate({
14664					width: width,
14665					height: height
14666				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc');
14667
14668				secondHolder.addClass(firstClass).css(transform, gpuAcceleration).animate({
14669					top: top,
14670					left: left,
14671					opacity: opts.styles.prevOpacity,
14672				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
14673					secondHolder.css(transform, '');
14674
14675					$('.ilightbox-thumbnail', vars.thumbnails).removeClass('ilightbox-active').eq(item).addClass('ilightbox-active');
14676					iL.positionThumbnails();
14677
14678					if (iL.items[item]) {
14679						if (!iL.items[item].options.mousewheel) vars.lockWheel = true;
14680						else vars.lockWheel = false;
14681
14682						if (!iL.items[item].options.swipe) vars.lockSwipe = true;
14683						else vars.lockSwipe = false;
14684					}
14685
14686					vars.isSwipe = false;
14687
14688					// Remove iframe & video from previous slide
14689					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
14690						$('div.ilightbox-container', secondHolder).empty();
14691					}
14692
14693					if (side == "next") {
14694						vars.nextPhoto = lastHolder,
14695							vars.prevPhoto = secondHolder,
14696							vars.holder = firstHolder;
14697
14698						vars.nextPhoto.hide();
14699
14700						vars.next = vars.next + 1,
14701							vars.prev = vars.current,
14702							vars.current = vars.current + 1;
14703
14704						if (opts.infinite) {
14705							if (vars.current > vars.total - 1) vars.current = 0;
14706							if (vars.current == vars.total - 1) vars.next = 0;
14707							if (vars.current == 0) vars.prev = vars.total - 1;
14708						}
14709
14710						iL.createUI();
14711
14712						if (!iL.items[vars.next])
14713							vars.nextLock = false;
14714						else
14715							iL.loadContent(iL.items[vars.next], 'next');
14716					} else {
14717						vars.prevPhoto = lastHolder;
14718						vars.nextPhoto = secondHolder;
14719						vars.holder = firstHolder;
14720
14721						vars.prevPhoto.hide();
14722
14723						vars.next = vars.current;
14724						vars.current = vars.prev;
14725						vars.prev = vars.current - 1;
14726
14727						if (opts.infinite) {
14728							if (vars.current == vars.total - 1) vars.next = 0;
14729							if (vars.current == 0) vars.prev = vars.total - 1;
14730						}
14731
14732						iL.createUI();
14733
14734						if (!iL.items[vars.prev])
14735							vars.prevLock = false;
14736						else
14737							iL.loadContent(iL.items[vars.prev], 'prev');
14738					}
14739
14740					// Add iframe & video content for current slide
14741					if (['iframe', 'video'].indexOf(iL.items[vars.current].type) !== -1) {
14742						iL.loadContent(iL.items[vars.current], 'current');
14743					}
14744
14745					if (opts.linkId) setTimeout(function() {
14746						vars.hashLock = false;
14747					}, 55);
14748
14749					// Configure arrow buttons
14750					if (!opts.infinite) {
14751						vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
14752
14753						if (vars.current == 0)
14754							vars.prevButton.add(vars.innerPrevButton).addClass('disabled');
14755						if (vars.current >= vars.total - 1)
14756							vars.nextButton.add(vars.innerNextButton).addClass('disabled');
14757					}
14758
14759					iL.repositionPhoto();
14760
14761					// Reset next cycle timeout
14762					iL.resetCycle();
14763
14764					//Trigger the onAfterChange callback
14765					if (typeof opts.callback.onAfterChange == 'function')
14766						opts.callback.onAfterChange.call(iL, iL.ui);
14767				});
14768
14769				top = (path == 'horizontal') ? getPixel(lastHolder, 'top') : ((side == "next") ? parseInt(-(winH / 2) - lastHolder.outerHeight()) : parseInt(top * 2)),
14770					left = (path == 'horizontal') ? ((side == "next") ? parseInt(-(winW / 2) - lastHolder.outerWidth()) : parseInt(left * 2)) : getPixel(lastHolder, 'left');
14771
14772				lastHolder.css(transform, gpuAcceleration).animate({
14773					top: top,
14774					left: left,
14775					opacity: opts.styles.nextOpacity
14776				}, switchSpeed, (vars.isSwipe) ? 'easeOutCirc' : 'easeInOutCirc', function() {
14777					lastHolder.css(transform, '');
14778				}).addClass(secondClass);
14779			}
14780		},
14781
14782		setCaption: function(obj, target) {
14783			var iL = this,
14784				caption = $('<div class="ilightbox-caption"></div>');
14785
14786			if (obj.caption) {
14787				caption.html(obj.caption);
14788				$('div.ilightbox-container', target).append(caption);
14789			}
14790		},
14791
14792		normalizeSocial: function(obj, url) {
14793			var iL = this,
14794				vars = iL.vars,
14795				opts = iL.options,
14796				baseURL = window.location.href;
14797
14798			$.each(obj, function(key, value) {
14799				if (!value)
14800					return true;
14801
14802				var item = key.toLowerCase(),
14803					source, text;
14804
14805				switch (item) {
14806					case 'facebook':
14807						source = "http://www.facebook.com/share.php?v=4&src=bm&u={URL}",
14808							text = "Share on Facebook";
14809						break;
14810					case 'twitter':
14811						source = "http://twitter.com/home?status={URL}",
14812							text = "Share on Twitter";
14813						break;
14814					case 'digg':
14815						source = "http://digg.com/submit?phase=2&url={URL}",
14816							text = "Share on Digg";
14817						break;
14818					case 'reddit':
14819						source = "http://reddit.com/submit?url={URL}",
14820							text = "Share on reddit";
14821						break;
14822				}
14823
14824				obj[key] = {
14825					URL: value.URL && absolutizeURI(baseURL, value.URL) || opts.linkId && window.location.href || typeof url !== 'string' && baseURL || url && absolutizeURI(baseURL, url) || baseURL,
14826					source: value.source || source || value.URL && absolutizeURI(baseURL, value.URL) || url && absolutizeURI(baseURL, url),
14827					text: value.text || text || "Share on " + key,
14828					width: (typeof(value.width) != 'undefined' && !isNaN(value.width)) ? parseInt(value.width) : 640,
14829					height: value.height || 360
14830				};
14831
14832			});
14833
14834			return obj;
14835		},
14836
14837		setSocial: function(obj, url, target) {
14838			var iL = this,
14839				socialBar = $('<div class="ilightbox-social"></div>'),
14840				buttons = '<ul>';
14841
14842			obj = iL.normalizeSocial(obj, url);
14843
14844			$.each(obj, function(key, value) {
14845				var item = key.toLowerCase(),
14846					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, '+'));
14847				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>';
14848			});
14849
14850			buttons += '</ul>';
14851
14852			socialBar.html(buttons);
14853			$('div.ilightbox-container', target).append(socialBar);
14854		},
14855
14856		fullScreenAction: function() {
14857			var iL = this,
14858				vars = iL.vars;
14859
14860			if (fullScreenApi.supportsFullScreen) {
14861				if (fullScreenApi.isFullScreen()) fullScreenApi.cancelFullScreen(document.documentElement);
14862				else fullScreenApi.requestFullScreen(document.documentElement);
14863			} else {
14864				iL.doFullscreen();
14865			}
14866		},
14867
14868		doFullscreen: function() {
14869			var iL = this,
14870				vars = iL.vars,
14871				viewport = getViewport(),
14872				opts = iL.options;
14873
14874			if (opts.fullAlone) {
14875				var currentHolder = vars.holder,
14876					current = iL.items[vars.current],
14877					windowWidth = viewport.width,
14878					windowHeight = viewport.height,
14879					elements = [currentHolder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.overlay, vars.toolbar, vars.thumbnails, vars.loader],
14880					hideElements = [vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
14881
14882				if (!vars.isInFullScreen) {
14883					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = true;
14884					vars.overlay.css({
14885						opacity: 1
14886					});
14887
14888					$.each(hideElements, function(i, element) {
14889						element.hide();
14890					});
14891
14892					vars.fullScreenButton.attr('title', opts.text.exitFullscreen);
14893
14894					if (opts.fullStretchTypes.indexOf(current.type) != -1) currentHolder.data({
14895						naturalWidthOld: currentHolder.data('naturalWidth'),
14896						naturalHeightOld: currentHolder.data('naturalHeight'),
14897						naturalWidth: windowWidth,
14898						naturalHeight: windowHeight
14899					});
14900					else {
14901						var viewport = current.options.fullViewPort || opts.fullViewPort || '',
14902							newWidth = windowWidth,
14903							newHeight = windowHeight,
14904							width = currentHolder.data('naturalWidth'),
14905							height = currentHolder.data('naturalHeight');
14906
14907						if (viewport.toLowerCase() == 'fill') {
14908							newHeight = (newWidth / width) * height;
14909
14910							if (newHeight < windowHeight) {
14911								newWidth = (windowHeight / height) * width,
14912									newHeight = windowHeight;
14913							}
14914						} else if (viewport.toLowerCase() == 'fit') {
14915							var dims = iL.getNewDimenstions(newWidth, newHeight, width, height, true);
14916
14917							newWidth = dims.width,
14918								newHeight = dims.height;
14919						} else if (viewport.toLowerCase() == 'stretch') {
14920							newWidth = newWidth,
14921								newHeight = newHeight;
14922						} else {
14923							var scale = (width > newWidth || height > newHeight) ? true : false,
14924								dims = iL.getNewDimenstions(newWidth, newHeight, width, height, scale);
14925							newWidth = dims.width,
14926								newHeight = dims.height;
14927						}
14928
14929						currentHolder.data({
14930							naturalWidthOld: currentHolder.data('naturalWidth'),
14931							naturalHeightOld: currentHolder.data('naturalHeight'),
14932							naturalWidth: newWidth,
14933							naturalHeight: newHeight
14934						});
14935					}
14936
14937					$.each(elements, function(key, val) {
14938						val.addClass('ilightbox-fullscreen');
14939					});
14940
14941					//Trigger the onEnterFullScreen callback
14942					if (typeof opts.callback.onEnterFullScreen == 'function') opts.callback.onEnterFullScreen.call(iL, iL.ui);
14943				} else {
14944					vars.isInFullScreen = vars.lockKey = vars.lockWheel = vars.lockSwipe = false;
14945					vars.overlay.css({
14946						opacity: iL.options.overlay.opacity
14947					});
14948
14949					$.each(hideElements, function(i, element) {
14950						element.show();
14951					});
14952
14953					vars.fullScreenButton.attr('title', opts.text.enterFullscreen);
14954
14955					currentHolder.data({
14956						naturalWidth: currentHolder.data('naturalWidthOld'),
14957						naturalHeight: currentHolder.data('naturalHeightOld'),
14958						naturalWidthOld: null,
14959						naturalHeightOld: null
14960					});
14961
14962					$.each(elements, function(key, val) {
14963						val.removeClass('ilightbox-fullscreen');
14964					});
14965
14966					//Trigger the onExitFullScreen callback
14967					if (typeof opts.callback.onExitFullScreen == 'function') opts.callback.onExitFullScreen.call(iL, iL.ui);
14968				}
14969			} else {
14970				if (!vars.isInFullScreen) vars.isInFullScreen = true;
14971				else vars.isInFullScreen = false;
14972			}
14973			iL.repositionPhoto(true);
14974		},
14975
14976		closeAction: function() {
14977			var iL = this,
14978				vars = iL.vars,
14979				opts = iL.options;
14980
14981			$win.unbind('.iLightBox');
14982			$doc.off('.iLightBox');
14983
14984			if (vars.isInFullScreen) fullScreenApi.cancelFullScreen(document.documentElement);
14985
14986			$('.ilightbox-overlay, .ilightbox-holder, .ilightbox-thumbnails').off('.iLightBox');
14987
14988			if (opts.hide.effect) vars.overlay.stop().fadeOut(opts.hide.speed, function() {
14989				vars.overlay.remove();
14990				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
14991			});
14992			else {
14993				vars.overlay.remove();
14994				vars.BODY.removeClass('ilightbox-noscroll').off('.iLightBox');
14995			}
14996
14997			var fadeOuts = [vars.toolbar, vars.holder, vars.nextPhoto, vars.prevPhoto, vars.nextButton, vars.prevButton, vars.loader, vars.thumbnails];
14998
14999			$.each(fadeOuts, function(i, element) {
15000				element.removeAttr('style').remove();
15001			});
15002
15003			vars.dontGenerateThumbs = vars.isInFullScreen = false;
15004
15005			window.iLightBox = null;
15006
15007			if (opts.linkId) {
15008				vars.hashLock = true;
15009				removeHash();
15010				setTimeout(function() {
15011					vars.hashLock = false;
15012				}, 55);
15013			}
15014
15015			vars.nextButton.add(vars.prevButton).add(vars.innerPrevButton).add(vars.innerNextButton).removeClass('disabled');
15016
15017			//Trigger the onHide callback
15018			if (typeof opts.callback.onHide == 'function') opts.callback.onHide.call(iL, iL.ui);
15019		},
15020
15021		repositionPhoto: function() {
15022			var iL = this,
15023				vars = iL.vars,
15024				opts = iL.options,
15025				path = opts.path.toLowerCase(),
15026				viewport = getViewport(),
15027				winWidth = viewport.width,
15028				winHeight = viewport.height;
15029
15030			if (viewport.width < UNCODE.mediaQuery) opts.styles.nextOffsetX = 0;
15031
15032			var thumbsOffsetW = (vars.isInFullScreen && opts.fullAlone || vars.isMobile) ? 0 : ((path == 'horizontal') ? 0 : vars.thumbnails.outerWidth()),
15033				thumbsOffsetH = vars.isMobile ? vars.toolbar.outerHeight() : ((vars.isInFullScreen && opts.fullAlone) ? 0 : ((path == 'horizontal') ? vars.thumbnails.outerHeight() : 0)),
15034				width = (vars.isInFullScreen && opts.fullAlone) ? winWidth : (winWidth - (opts.styles.pageOffsetX)),
15035				height = (vars.isInFullScreen && opts.fullAlone) ? winHeight : (winHeight - (opts.styles.pageOffsetY)),
15036				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,
15037				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)));
15038
15039			var elObject = {
15040				type: 'current',
15041				width: width,
15042				height: height,
15043				item: iL.items[vars.current],
15044				offsetW: offsetW,
15045				offsetH: offsetH,
15046				thumbsOffsetW: thumbsOffsetW,
15047				thumbsOffsetH: thumbsOffsetH,
15048				animate: arguments.length,
15049				holder: vars.holder
15050			};
15051
15052			iL.repositionEl(elObject);
15053
15054			if (iL.items[vars.next]) {
15055				elObject = $.extend(elObject, {
15056					type: 'next',
15057					item: iL.items[vars.next],
15058					offsetX: opts.styles.nextOffsetX,
15059					offsetY: opts.styles.nextOffsetY,
15060					holder: vars.nextPhoto
15061				});
15062
15063				iL.repositionEl(elObject);
15064			}
15065
15066			if (iL.items[vars.prev]) {
15067				elObject = $.extend(elObject, {
15068					type: 'prev',
15069					item: iL.items[vars.prev],
15070					offsetX: opts.styles.nextOffsetX,
15071					offsetY: opts.styles.prevOffsetY,
15072					holder: vars.prevPhoto
15073				});
15074
15075				iL.repositionEl(elObject);
15076			}
15077
15078			var loaderCss = (path == "horizontal") ? {
15079				left: parseInt((width / 2) - (vars.loader.outerWidth() / 2))
15080			} : {
15081				top: parseInt((height / 2) - (vars.loader.outerHeight() / 2))
15082			};
15083			vars.loader.css(loaderCss);
15084		},
15085
15086		repositionEl: function(obj) {
15087			var iL = this,
15088				vars = iL.vars,
15089				opts = iL.options,
15090				path = opts.path.toLowerCase(),
15091				widthAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.width : (obj.width - obj.offsetW)) : (obj.width - obj.offsetW),
15092				heightAvail = (obj.type == 'current') ? ((vars.isInFullScreen && opts.fullAlone) ? obj.height : (obj.height - obj.offsetH)) : (obj.height - obj.offsetH),
15093				itemParent = obj.item,
15094				item = obj.item.options,
15095				holder = obj.holder,
15096				offsetX = obj.offsetX || 0,
15097				offsetY = obj.offsetY || 0,
15098				//Uncode change ##START##
15099				toolbarHeight = $('.ilightbox-inner-toolbar', holder).length ? parseInt( $('.ilightbox-inner-toolbar', holder).outerHeight() ) : 0,
15100				//Uncode change ##END##
15101				thumbsOffsetW = obj.thumbsOffsetW,
15102				thumbsOffsetH = obj.thumbsOffsetH;
15103
15104			if (obj.type == 'current') {
15105				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);
15106				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);
15107			} else {
15108				if (typeof item.width == 'number' && item.width) widthAvail = (item.width > widthAvail) ? widthAvail : item.width;
15109				if (typeof item.height == 'number' && item.height) heightAvail = (item.height > heightAvail) ? heightAvail : item.height;
15110			}
15111
15112
15113			//Uncode change ##START##
15114			heightAvail = parseInt(heightAvail - toolbarHeight);
15115			// heightAvail = parseInt(heightAvail - $('.ilightbox-inner-toolbar', holder).outerHeight());
15116			//Uncode change ##END##
15117
15118			var width = (typeof item.width == 'string' && item.width.indexOf('%') != -1) ? percentToValue(parseInt(item.width.replace('%', '')), obj.width) : holder.data('naturalWidth'),
15119				height = (typeof item.height == 'string' && item.height.indexOf('%') != -1) ? percentToValue(parseInt(item.height.replace('%', '')), obj.height) : holder.data('naturalHeight');
15120
15121			var dims = ((typeof item.width == 'string' && item.width.indexOf('%') != -1 || typeof item.height == 'string' && item.height.indexOf('%') != -1) ? {
15122					width: width,
15123					height: height
15124				} : iL.getNewDimenstions(widthAvail, heightAvail, width, height)),
15125				newDims = $.extend({}, dims, {});
15126
15127			if (obj.type == 'prev' || obj.type == 'next')
15128				width = parseInt(dims.width * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale)),
15129				height = parseInt(dims.height * ((obj.type == 'next') ? opts.styles.nextScale : opts.styles.prevScale));
15130			else
15131				width = dims.width,
15132				height = dims.height;
15133
15134			var widthDiff = parseInt((getPixel(holder, 'padding-left') + getPixel(holder, 'padding-right') + getPixel(holder, 'border-left-width') + getPixel(holder, 'border-right-width')) / 2),
15135				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);
15136
15137			switch (obj.type) {
15138				case 'current':
15139					var top = parseInt((obj.height / 2) - (height / 2) - heightDiff - (thumbsOffsetH / 2)),
15140						left = parseInt((obj.width / 2) - (width / 2) - widthDiff - (thumbsOffsetW / 2));
15141					break;
15142
15143				case 'next':
15144					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(obj.height - offsetX - heightDiff - (thumbsOffsetH / 2)),
15145						left = (path == 'horizontal') ? parseInt(obj.width - offsetX - widthDiff - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - (width / 2) - widthDiff - offsetY - (thumbsOffsetW / 2));
15146					break;
15147
15148				case 'prev':
15149					var top = (path == 'horizontal') ? parseInt((obj.height / 2) - offsetY - (height / 2) - heightDiff - (thumbsOffsetH / 2)) : parseInt(offsetX - heightDiff - height - (thumbsOffsetH / 2)),
15150						left = (path == 'horizontal') ? parseInt(offsetX - widthDiff - width - (thumbsOffsetW / 2)) : parseInt((obj.width / 2) - offsetY - (width / 2) - widthDiff - (thumbsOffsetW / 2));
15151					break;
15152			}
15153
15154			holder.data('offset', {
15155				top: top,
15156				left: left,
15157				newDims: newDims,
15158				diff: {
15159					W: widthDiff,
15160					H: heightDiff
15161				},
15162				thumbsOffset: {
15163					W: thumbsOffsetW,
15164					H: thumbsOffsetH
15165				},
15166				object: obj
15167			});
15168
15169			var opacityMobile;
15170			if ( isMobile ) {
15171				opacityMobile = {
15172					opacity: 1,
15173					top: top,
15174					left: left
15175				};
15176			} else {
15177				opacityMobile = {
15178					top: top,
15179					left: left
15180				};
15181			}
15182
15183			if (obj.animate > 0 && opts.effects.reposition) {
15184				holder.css(transform, gpuAcceleration).stop().animate(
15185					opacityMobile,
15186					opts.effects.repositionSpeed, 'easeOutCirc', function() {
15187					holder.css(transform, '');
15188				});
15189				$('div.ilightbox-container', holder).stop().animate({
15190					width: width,
15191					height: height
15192				}, opts.effects.repositionSpeed, 'easeOutCirc');
15193				$('div.ilightbox-inner-toolbar', holder).stop().animate({
15194					width: width
15195				}, opts.effects.repositionSpeed, 'easeOutCirc', function() {
15196					$(this).css('overflow', 'visible');
15197				});
15198			} else {
15199				holder.css(opacityMobile);
15200				$('div.ilightbox-container', holder).css({
15201					width: width,
15202					height: height
15203				});
15204				$('div.ilightbox-inner-toolbar', holder).css({
15205					width: width
15206				});
15207			}
15208		},
15209
15210
15211		resume: function(priority) {
15212			var iL = this,
15213				vars = iL.vars,
15214				opts = iL.options;
15215
15216			if (!opts.slideshow.pauseTime || opts.controls.slideshow && vars.total <= 1 || priority < vars.isPaused) {
15217				return;
15218			}
15219
15220			vars.isPaused = 0;
15221
15222			if (vars.cycleID) {
15223				vars.cycleID = clearTimeout(vars.cycleID);
15224			}
15225
15226			vars.cycleID = setTimeout(function() {
15227				if (vars.current == vars.total - 1) iL.goTo(0);
15228				else iL.moveTo('next');
15229			}, opts.slideshow.pauseTime);
15230		},
15231
15232		pause: function(priority) {
15233			var iL = this,
15234				vars = iL.vars,
15235				opts = iL.options;
15236
15237			if (priority < vars.isPaused) {
15238				return;
15239			}
15240
15241			vars.isPaused = priority || 100;
15242
15243			if (vars.cycleID) {
15244				vars.cycleID = clearTimeout(vars.cycleID);
15245			}
15246		},
15247
15248		resetCycle: function() {
15249			var iL = this,
15250				vars = iL.vars,
15251				opts = iL.options;
15252
15253			if (opts.controls.slideshow && vars.cycleID && !vars.isPaused) {
15254				iL.resume();
15255			}
15256		},
15257
15258		getNewDimenstions: function(width, height, width_old, height_old, thumb) {
15259			var iL = this;
15260
15261			if (!width) factor = height / height_old;
15262			else if (!height) factor = width / width_old;
15263			else factor = min(width / width_old, height / height_old);
15264
15265			if (!thumb) {
15266				if (factor > iL.options.maxScale) factor = iL.options.maxScale;
15267				else if (factor < iL.options.minScale) factor = iL.options.minScale;
15268			}
15269
15270			var final_width = (iL.options.keepAspectRatio) ? round(width_old * factor) : width,
15271				final_height = (iL.options.keepAspectRatio) ? round(height_old * factor) : height;
15272
15273			return {
15274				width: final_width,
15275				height: final_height,
15276				ratio: factor
15277			};
15278		},
15279
15280		setOption: function(options) {
15281			var iL = this;
15282
15283			iL.options = $.extend(true, iL.options, options || {});
15284			iL.refresh();
15285		},
15286
15287		availPlugins: function() {
15288			var iL = this,
15289				testEl = document.createElement("video");
15290
15291			iL.plugins = {
15292				flash: !isMobile,
15293				quicktime: (parseInt(PluginDetect.getVersion("QuickTime")) >= 0) ? true : false,
15294				html5H264: !!(testEl.canPlayType && testEl.canPlayType('video/mp4').replace(/no/, '')),
15295				html5WebM: !!(testEl.canPlayType && testEl.canPlayType('video/webm').replace(/no/, '')),
15296				html5Vorbis: !!(testEl.canPlayType && testEl.canPlayType('video/ogg').replace(/no/, '')),
15297				html5QuickTime: !!(testEl.canPlayType && testEl.canPlayType('video/quicktime').replace(/no/, ''))
15298			};
15299		},
15300
15301		addContent: function(element, obj) {
15302			var iL = this,
15303				el;
15304
15305			switch (obj.type) {
15306				case 'video':
15307					var HTML5 = false,
15308						videoType = obj.videoType,
15309						html5video = obj.options.html5video;
15310
15311					if (((videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v') || html5video.h264) && iL.plugins.html5H264)
15312						obj.ext = 'mp4',
15313						obj.URL = html5video.h264 || obj.URL;
15314					else if (html5video.webm && iL.plugins.html5WebM)
15315						obj.ext = 'webm',
15316						obj.URL = html5video.webm || obj.URL;
15317					else if (html5video.ogg && iL.plugins.html5Vorbis)
15318						obj.ext = 'ogv',
15319						obj.URL = html5video.ogg || obj.URL;
15320
15321					if (iL.plugins.html5H264 && (videoType == 'video/mp4' || obj.ext == 'mp4' || obj.ext == 'm4v')) HTML5 = true, videoType = "video/mp4";
15322					else if (iL.plugins.html5WebM && (videoType == 'video/webm' || obj.ext == 'webm')) HTML5 = true, videoType = "video/webm";
15323					else if (iL.plugins.html5Vorbis && (videoType == 'video/ogg' || obj.ext == 'ogv')) HTML5 = true, videoType = "video/ogg";
15324					else if (iL.plugins.html5QuickTime && (videoType == 'video/quicktime' || obj.ext == 'mov' || obj.ext == 'qt')) HTML5 = true, videoType = "video/quicktime";
15325
15326					if (HTML5) {
15327						el = $('<video />
15327', {
15328							"width": "100%",
15329							"height": "100%",
15330							"preload": html5video.preload,
15331							"autoplay": html5video.autoplay,
15332							"loop": html5video.loop,
15333							"poster": html5video.poster,
15334							"controls": html5video.controls,
15335							"controlslist": "nodownload"
15336						}).append($('<source />', {
15337							"src": obj.URL,
15338							"type": videoType
15339						}));
15340					} else {
15341						if (!iL.plugins.quicktime) el = $('<span />', {
15342							"class": "ilightbox-alert",
15343							html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.quicktime).replace('{type}', 'QuickTime')
15344						});
15345						else {
15346
15347							el = $('<object />', {
15348								"type": "video/quicktime",
15349								"pluginspage": pluginspages.quicktime
15350							}).attr({
15351								"data": obj.URL,
15352								"width": "100%",
15353								"height": "100%"
15354							}).append($('<param />', {
15355								"name": "src",
15356								"value": obj.URL
15357							})).append($('<param />', {
15358								"name": "autoplay",
15359								"value": "false"
15360							})).append($('<param />', {
15361								"name": "loop",
15362								"value": "false"
15363							})).append($('<param />', {
15364								"name": "scale",
15365								"value": "tofit"
15366							}));
15367
15368							if (browser.msie) el = QT_GenerateOBJECTText(obj.URL, '100%', '100%', '', 'SCALE', 'tofit', 'AUTOPLAY', 'false', 'LOOP', 'false');
15369						}
15370					}
15371
15372					break;
15373
15374				case 'flash':
15375					if (!iL.plugins.flash) el = $('<span />', {
15376						"class": "ilightbox-alert",
15377						html: iL.options.errors.missingPlugin.replace('{pluginspage}', pluginspages.flash).replace('{type}', 'Adobe Flash player')
15378					});
15379					else {
15380						var flashvars = "",
15381							i = 0;
15382
15383						if (obj.options.flashvars) $.each(obj.options.flashvars, function(k, v) {
15384							if (i != 0) flashvars += "&";
15385							flashvars += k + "=" + encodeURIComponent(v);
15386							i++;
15387						});
15388						else flashvars = null;
15389
15390						el = $('<embed />').attr({
15391							"type": "application/x-shockwave-flash",
15392							"src": obj.URL,
15393							"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
15394							"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
15395							"quality": "high",
15396							"bgcolor": "#000000",
15397							"play": "true",
15398							"loop": "true",
15399							"menu": "true",
15400							"wmode": "transparent",
15401							"scale": "showall",
15402							"allowScriptAccess": "always",
15403							"allowFullScreen": "true",
15404							"flashvars": flashvars,
15405							"fullscreen": "yes"
15406						});
15407					}
15408
15409					break;
15410
15411				case 'iframe':
15412					el = $('<iframe />').attr({
15413						"width": (typeof obj.options.width == 'number' && obj.options.width && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.width : "100%",
15414						"height": (typeof obj.options.height == 'number' && obj.options.height && iL.options.minScale == '1' && iL.options.maxScale == '1') ? obj.options.height : "100%",
15415						src: obj.URL,
15416						frameborder: 0,
15417						'hspace': 0,
15418						'vspace': 0,
15419						'scrolling': supportTouch ? 'auto' : 'scroll',
15420						'webkitAllowFullScreen': '',
15421						'mozallowfullscreen': '',
15422						'allowFullScreen': ''
15423					});
15424
15425					break;
15426
15427				case 'inline':
15428					el = $('<div class="ilightbox-wrapper"></div>').html($(obj.URL).clone(true));
15429
15430					break;
15431
15432				case 'html':
15433					var object = obj.URL,
15434						el;
15435
15436					if (object[0].nodeName) {
15437						el = $('<div class="ilightbox-wrapper"></div>').html(object);
15438					} else {
15439						var dom = $(obj.URL),
15440							html = (dom.selector) ? $('<div>' + dom + '</div>') : dom;
15441						el = $('<div class="ilightbox-wrapper"></div>').html(html);
15442					}
15443
15444					break;
15445			}
15446
15447			$('div.ilightbox-container', element).empty().html(el);
15448
15449			// For fixing Chrome about just playing the video for first time
15450			if (el[0].tagName.toLowerCase() === 'video' && browser.webkit) setTimeout(function() {
15451				var src = el[0].currentSrc + '?' + floor(random() * 30000);
15452				el[0].currentSrc = src;
15453				el[0].src = src;
15454			});
15455
15456			return el;
15457		},
15458
15459		ogpRecognition: function(obj, callback) {
15460			var iL = this,
15461				url = obj.URL;
15462
15463			iL.showLoader();
15464			doAjax(url, function(data) {
15465				iL.hideLoader();
15466				if (data) {
15467					var object = new Object();
15468
15469					object.length = false,
15470					object.url = data.url;
15471
15472					if (data.status == 200) {
15473						var result = data.results,
15474							type = result.type,
15475							source = result.source;
15476
15477						object.source = source.src,
15478						object.width = source.width && parseInt(source.width) || 0,
15479						object.height = source.height && parseInt(source.height) || 0,
15480						object.type = type,
15481						object.thumbnail = source.thumbnail || result.images && result.images[0],
15482						object.html5video = result.html5video || {},
15483						object.length = true;
15484
15485						if (source.type == 'application/x-shockwave-flash') object.type = "flash";
15486						else if (source.type.indexOf("video/") != -1) object.type = "video";
15487						else if (source.type.indexOf("/html") != -1) object.type = "iframe";
15488						else if (source.type.indexOf("image/") != -1) object.type = "image";
15489
15490					} else if (typeof data.response != 'undefined')
15491						throw data.response;
15492
15493					callback.call(this, object.length ? object : false);
15494				}
15495			});
15496		},
15497
15498		hashChangeHandler: function(url) {
15499			var iL = this,
15500				vars = iL.vars,
15501				opts = iL.options,
15502				URL = url || window.location.href,
15503				hash = parseURI(URL).hash,
15504				split = hash.split('/'),
15505				index = split[1];
15506
15507			if (vars.hashLock || ('#' + opts.linkId != split[0] && hash.length > 1)) return;
15508
15509			if (index) {
15510				var target = split[1] || 0;
15511				if (iL.items[target]) {
15512					var overlay = $('.ilightbox-overlay');
15513					if (overlay.length && overlay.attr('linkid') == opts.linkId) {
15514						iL.goTo(target);
15515					} else {
15516						iL.itemsObject[target].trigger(ishybrid ? "itap click" : supportTouch ? 'itap' : 'click');
15517						//iL.goTo(target);
15518					}
15519				} else {
15520					var overlay = $('.ilightbox-overlay');
15521					if (overlay.length) iL.closeAction();
15522				}
15523			} else {
15524				var overlay = $('.ilightbox-overlay');
15525				if (overlay.length) iL.closeAction();
15526			}
15527		}
15528	};
15529
15530	/**
15531	 * Parse style to pixels.
15532	 *
15533	 * @param {Object}   $element   jQuery object with element.
15534	 * @param {Property} property   CSS property to get the pixels from.
15535	 *
15536	 * @return {Int}
15537	 */
15538	function getPixel($element, property) {
15539		return parseInt($element.css(property), 10) || 0;
15540	}
15541
15542	/**
15543	 * Make sure that number is within the limits.
15544	 *
15545	 * @param {Number} number
15546	 * @param {Number} min
15547	 * @param {Number} max
15548	 *
15549	 * @return {Number}
15550	 */
15551	function within(number, min, max) {
15552		return number < min ? min : number > max ? max : number;
15553	}
15554
15555	/**
15556	 * Get viewport/window size (width and height).
15557	 *
15558	 * @return {Object}
15559	 */
15560	function getViewport() {
15561		var e = window,
15562			a = 'inner';
15563		if (!('innerWidth' in window)) {
15564			a = 'client';
15565			e = document.documentElement || document.body;
15566		}
15567		return {
15568			width: e[a + 'Width'],
15569			height: e[a + 'Height']
15570		}
15571	}
15572
15573	/**
15574	 * Remove hash tag from the URL
15575	 *
15576	 * @return {Void}
15577	 */
15578	function removeHash() {
15579		var scroll = getScrollXY();
15580
15581		//UNCODE change
15582		//window.location.hash = "";
15583		history.pushState("", document.title, window.location.pathname + window.location.search);
15584
15585		// Restore the scroll offset, should be flicker free
15586		window.scrollTo(scroll.x, scroll.y);
15587	}
15588
15589	/**
15590	 * Do the ajax requests with callback.
15591	 *
15592	 * @param {String}   url
15593	 * @param {Function} callback
15594	 *
15595	 * @return {Void}
15596	 */
15597	function doAjax(url, callback) {
15598		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');
15599		$.ajax({
15600			url: url,
15601			dataType: 'jsonp'
15602		});
15603
15604		iLCallback = function(data) {
15605			callback.call(this, data);
15606		};
15607	}
15608
15609	/**
15610	 * Find image from DOM elements
15611	 *
15612	 * @param {Element} element
15613	 *
15614	 * @return {Void}
15615	 */
15616	function findImageInElement(element) {
15617		var elements = $('*', element),
15618			imagesArr = new Array();
15619
15620		elements.each(function() {
15621			var url = "",
15622				element = this;
15623
15624			if ($(element).css("background-image") != "none") {
15625				url = $(element).css("background-image");
15626			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
15627				url = $(element).attr("src");
15628			}
15629
15630			if (url.indexOf("gradient") == -1) {
15631				url = url.replace(/url\(\"/g, "");
15632				url = url.replace(/url\(/g, "");
15633				url = url.replace(/\"\)/g, "");
15634				url = url.replace(/\)/g, "");
15635
15636				var urls = url.split(",");
15637
15638				for (var i = 0; i < urls.length; i++) {
15639					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
15640						var extra = "";
15641						if (browser.msie && browser.version < 9) {
15642							extra = "?" + floor(random() * 3000);
15643						}
15644						imagesArr.push(urls[i] + extra);
15645					}
15646				}
15647			}
15648		});
15649
15650		return imagesArr;
15651	}
15652
15653	/**
15654	 * Get file extension.
15655	 *
15656	 * @param {String} URL
15657	 *
15658	 * @return {String}
15659	 */
15660	function getExtension(URL) {
15661		if (URL !== null) {
15662			//UNCODE: fix issue to detect media type with query strings
15663			var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL;
15664			ext = ext.split('.').pop().toLowerCase();
15665
15666			return ext;
15667		}
15668	}
15669
15670	/**
15671	 * Get type via extension.
15672	 *
15673	 * @param {String} URL
15674	 *
15675	 * @return {String}
15676	 */
15677	function getTypeByExtension(URL) {
15678		var type,
15679			ext = getExtension(URL);
15680
15681		//Uncode addition ##START##
15682		if (URL == undefined) {
15683			return false;
15684		}
15685		//Uncode addition ##END##
15686
15687		if (extensions.image.indexOf(ext) !== -1) type = 'image';
15688		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
15689		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
15690		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
15691		else type = 'iframe';
15692
15693		return type;
15694	}
15695
15696	/**
15697	 * Return value from percent of a number.
15698	 *
15699	 * @param {Number} percent
15700	 * @param {Number} total
15701	 *
15702	 * @return {Number}
15703	 */
15704	function percentToValue(percent, total) {
15705		return parseInt((total / 100) * percent);
15706	}
15707
15708	/**
15709	 * A JavaScript equivalent of PHP’s parse_url.
15710	 *
15711	 * @param {String} url           The URL to parse.
15712	 *
15713	 * @return {Mixed}
15714	 */
15715	function parseURI(url) {
15716		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
15717		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
15718		return (m ? {
15719			href: m[0] || '',
15720			protocol: m[1] || '',
15721			authority: m[2] || '',
15722			host: m[3] || '',
15723			hostname: m[4] || '',
15724			port: m[5] || '',
15725			pathname: m[6] || '',
15726			search: m[7] || '',
15727			hash: m[8] || ''
15728		} : null);
15729	}
15730
15731	/**
15732	 * Gets the absolute URI.
15733	 *
15734	 * @param {String} href     The relative URL.
15735	 * @param {String} base     The base URL.
15736	 *
15737	 * @return {String}         The absolute URL.
15738	 */
15739	function absolutizeURI(base, href) { // RFC 3986
15740		var iL = this;
15741
15742		function removeDotSegments(input) {
15743			var output = [];
15744			input.replace(/^(\.\.?(\/|$))+/, '')
15745				.replace(/\/(\.(\/|$))+/g, '/')
15746				.replace(/\/\.\.$/, '/../')
15747				.replace(/\/?[^\/]*/g, function(p) {
15748					if (p === '/..') {
15749						output.pop();
15750					} else {
15751						output.push(p);
15752					}
15753				});
15754			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
15755		}
15756
15757		href = parseURI(href || '');
15758		base = parseURI(base || '');
15759
15760		return !href || !base ? null : (href.protocol || base.protocol) +
15761			(href.protocol || href.authority ? href.authority : base.authority) +
15762			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)) +
15763			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
15764			href.hash;
15765	}
15766
15767	/**
15768	 * A JavaScript equivalent of PHP’s version_compare.
15769	 *
15770	 * @param {String} v1
15771	 * @param {String} v2
15772	 * @param {String} operator
15773	 *
15774	 * @return {Boolean}
15775	 */
15776	function version_compare(v1, v2, operator) {
15777		this.php_js = this.php_js || {};
15778		this.php_js.ENV = this.php_js.ENV || {};
15779		var i = 0,
15780			x = 0,
15781			compare = 0,
15782			vm = {
15783				'dev': -6,
15784				'alpha': -5,
15785				'a': -5,
15786				'beta': -4,
15787				'b': -4,
15788				'RC': -3,
15789				'rc': -3,
15790				'#': -2,
15791				'p': 1,
15792				'pl': 1
15793			},
15794			prepVersion = function(v) {
15795				v = ('' + v).replace(/[_\-+]/g, '.');
15796				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
15797				return (!v.length ? [-8] : v.split('.'));
15798			},
15799			numVersion = function(v) {
15800				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
15801			};
15802		v1 = prepVersion(v1);
15803		v2 = prepVersion(v2);
15804		x = max(v1.length, v2.length);
15805		for (i = 0; i < x; i++) {
15806			if (v1[i] == v2[i]) {
15807				continue;
15808			}
15809			v1[i] = numVersion(v1[i]);
15810			v2[i] = numVersion(v2[i]);
15811			if (v1[i] < v2[i]) {
15812				compare = -1;
15813				break;
15814			} else if (v1[i] > v2[i]) {
15815				compare = 1;
15816				break;
15817			}
15818		}
15819		if (!operator) {
15820			return compare;
15821		}
15822
15823		switch (operator) {
15824			case '>':
15825			case 'gt':
15826				return (compare > 0);
15827			case '>=':
15828			case 'ge':
15829				return (compare >= 0);
15830			case '<=':
15831			case 'le':
15832				return (compare <= 0);
15833			case '==':
15834			case '=':
15835			case 'eq':
15836				return (compare === 0);
15837			case '<>':
15838			case '!=':
15839			case 'ne':
15840				return (compare !== 0);
15841			case '':
15842			case '<':
15843			case 'lt':
15844				return (compare < 0);
15845			default:
15846				return null;
15847		}
15848	}
15849
15850
15851	// Begin the iLightBox plugin
15852	$.fn.iLightBox = function() {
15853
15854		var args = arguments,
15855			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
15856			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
15857
15858		if (!opt) opt = {};
15859
15860		// Default options. Play carefully.
15861		var options = $.extend(true, {
15862			attr: 'href',
15863			path: 'vertical',
15864			skin: 'dark',
15865			linkId: false,
15866			infinite: false,
15867			startFrom: 0,
15868			randomStart: false,
15869			keepAspectRatio: true,
15870			maxScale: 1,
15871			minScale: .2,
15872			innerToolbar: false,
15873			smartRecognition: false,
15874			mobileOptimizer: true,
15875			fullAlone: true,
15876			fullViewPort: null,
15877			fullStretchTypes: 'flash, video',
15878			overlay: {
15879				blur: true,
15880				opacity: .85
15881			},
15882			controls: {
15883				arrows: false,
15884				slideshow: false,
15885				toolbar: true,
15886				fullscreen: true,
15887				thumbnail: true,
15888				keyboard: true,
15889				mousewheel: true,
15890				swipe: true
15891			},
15892			keyboard: {
15893				left: true, // previous
15894				right: true, // next
15895				up: true, // previous
15896				down: true, // next
15897				esc: true, // close
15898				shift_enter: true // fullscreen
15899			},
15900			show: {
15901				effect: true,
15902				speed: 300,
15903				title: true
15904			},
15905			hide: {
15906				effect: true,
15907				speed: 300
15908			},
15909			caption: {
15910				start: true,
15911				show: 'mouseenter',
15912				hide: 'mouseleave'
15913			},
15914			social: {
15915				start: true,
15916				show: 'mouseenter',
15917				hide: 'mouseleave',
15918				buttons: false
15919			},
15920			styles: {
15921				pageOffsetX: 0,
15922				pageOffsetY: 0,
15923				nextOffsetX: 45,
15924				nextOffsetY: 0,
15925				nextOpacity: 1,
15926				nextScale: 1,
15927				prevOffsetX: 45,
15928				prevOffsetY: 0,
15929				prevOpacity: 1,
15930				prevScale: 1
15931			},
15932			thumbnails: {
15933				maxWidth: 120,
15934				maxHeight: 80,
15935				normalOpacity: 1,
15936				activeOpacity: .6
15937			},
15938			effects: {
15939				reposition: true,
15940				repositionSpeed: 200,
15941				switchSpeed: 500,
15942				loadedFadeSpeed: 180,
15943				fadeSpeed: 200
15944			},
15945			slideshow: {
15946				pauseTime: 5000,
15947				pauseOnHover: false,
15948				startPaused: true
15949			},
15950			text: {
15951				close: "Press Esc to close",
15952				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
15953				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
15954				slideShow: "Slideshow",
15955				next: "Next",
15956				previous: "Previous"
15957			},
15958			errors: {
15959				loadImage: "An error occurred when trying to load photo.",
15960				loadContents: "An error occurred when trying to load contents.",
15961				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
15962			},
15963			ajaxSetup: {
15964				url: '',
15965				beforeSend: function(jqXHR, settings) {},
15966				cache: false,
15967				complete: function(jqXHR, textStatus) {},
15968				crossDomain: false,
15969				error: function(jqXHR, textStatus, errorThrown) {},
15970				success: function(data, textStatus, jqXHR) {},
15971				global: true,
15972				ifModified: false,
15973				username: null,
15974				password: null,
15975				type: 'GET'
15976			},
15977			callback: {}
15978		}, opt);
15979
15980		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
15981
15982		items = $.isArray(items) ? items : new Array();
15983
15984		if (typeof args[0] == 'string') items[0] = args[0];
15985
15986		if (version_compare($.fn.jquery, '1.8', '>=')) {
15987			var iLB = new iLightBox($(this), options, items, instant);
15988			return {
15989				close: function() {
15990					iLB.closeAction();
15991				},
15992				fullscreen: function() {
15993					iLB.fullScreenAction();
15994				},
15995				moveNext: function() {
15996					iLB.moveTo('next');
15997				},
15998				movePrev: function() {
15999					iLB.moveTo('prev');
16000				},
16001				goTo: function(index) {
16002					iLB.goTo(index);
16003				},
16004				refresh: function() {
16005					iLB.refresh();
16006				},
16007				reposition: function() {
16008					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
16009				},
16010				setOption: function(options) {
16011					iLB.setOption(options);
16012				},
16013				destroy: function() {
16014					iLB.closeAction();
16015					iLB.dispatchItemsEvents();
16016				}
16017			};
16018		} else {
16019			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
16020		}
16021
16022	};
16023
16024
16025	$.iLightBox = function() {
16026		return $.fn.iLightBox(arguments[0], arguments[1]);
16027	};
16028
16029	function getScrollXY() {
16030		var scrOfX = 0,
16031			scrOfY = 0;
16032		if (typeof(window.pageYOffset) == 'number') {
16033			//Netscape compliant
16034			scrOfY = window.pageYOffset;
16035			scrOfX = window.pageXOffset;
16036		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
16037			//DOM compliant
16038			scrOfY = document.body.scrollTop;
16039			scrOfX = document.body.scrollLeft;
16040		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
16041			//IE6 standards compliant mode
16042			scrOfY = document.documentElement.scrollTop;
16043			scrOfX = document.documentElement.scrollLeft;
16044		}
16045		return {
16046			x: scrOfX,
16047			y: scrOfY
16048		};
16049	}
16050
16051	(function() {
16052		// add new event shortcuts
16053		$.each(("touchstart touchmove touchend " +
16054			"tap taphold " +
16055			"swipe swipeleft swiperight " +
16056			"scrollstart scrollstop").split(" "), function(i, name) {
16057
16058			$.fn[name] = function(fn) {
16059				return fn ? this.bind(name, fn) : this.trigger(name);
16060			};
16061
16062			// jQuery < 1.8
16063			// if ($.attrFn) {
16064			// 	$.attrFn[name] = true;
16065			// }
16066		});
16067
16068		var tapSettings = {
16069			startEvent: 'touchstart.iTap',
16070			endEvent: 'touchend.iTap'
16071		};
16072
16073		// tap Event:
16074		$.event.special.itap = {
16075			setup: function() {
16076
16077				var self = this,
16078					$self = $(this),
16079					start, stop;
16080
16081				$self.bind(tapSettings.startEvent, function(event) {
16082					start = getScrollXY();
16083
16084					$self.one(tapSettings.endEvent, function(event) {
16085						stop = getScrollXY();
16086
16087						var orgEvent = event || window.event;
16088						event = $.event.fix(orgEvent);
16089						event.type = "itap";
16090
16091						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
16092
16093						start = stop = undefined;
16094					});
16095				});
16096			},
16097
16098			teardown: function() {
16099				$(this).unbind(tapSettings.startEvent);
16100			}
16101		};
16102	}());
16103
16104
16105	//Fullscreen API
16106	(function() {
16107		fullScreenApi = {
16108				supportsFullScreen: false,
16109				isFullScreen: function() {
16110					return false;
16111				},
16112				requestFullScreen: function() {},
16113				cancelFullScreen: function() {},
16114				fullScreenEventName: '',
16115				prefix: ''
16116			},
16117			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
16118
16119		// check for native support
16120		if (typeof document.cancelFullScreen != 'undefined') {
16121			fullScreenApi.supportsFullScreen = true;
16122		} else {
16123			// check for fullscreen support by vendor prefix
16124			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
16125				fullScreenApi.prefix = browserPrefixes[i];
16126
16127				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
16128					fullScreenApi.supportsFullScreen = true;
16129
16130					break;
16131				}
16132			}
16133		}
16134
16135		// update methods to do something useful
16136		if (fullScreenApi.supportsFullScreen) {
16137			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
16138
16139			fullScreenApi.isFullScreen = function() {
16140				switch (this.prefix) {
16141					case '':
16142						return document.fullScreen;
16143					case 'webkit':
16144						return document.webkitIsFullScreen;
16145					default:
16146						return document[this.prefix + 'FullScreen'];
16147				}
16148			}
16149			fullScreenApi.requestFullScreen = function(el) {
16150				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
16151			}
16152			fullScreenApi.cancelFullScreen = function(el) {
16153				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
16154			}
16155		}
16156	}());
16157
16158	// Browser detect
16159	(function() {
16160		function uaMatch(ua) {
16161			ua = ua.toLowerCase();
16162
16163			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
16164				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
16165				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
16166				/(msie) ([\w.]+)/.exec(ua) ||
16167				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
16168
16169			return {
16170				browser: match[1] || "",
16171				version: match[2] || "0"
16172			};
16173		}
16174
16175		var matched = uaMatch(navigator.userAgent);
16176		browser = {};
16177
16178		if (matched.browser) {
16179			browser[matched.browser] = true;
16180			browser.version = matched.version;
16181		}
16182
16183		// Chrome is Webkit, but Webkit is also Safari.
16184		if (browser.chrome) {
16185			browser.webkit = true;
16186		} else if (browser.webkit) {
16187			browser.safari = true;
16188		}
16189	}());
16190
16191	// Feature detects
16192	(function() {
16193		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
16194		var el = document.createElement('div');
16195
16196		function testProp(prop) {
16197			for (var p = 0, pl = prefixes.length; p < pl; p++) {
16198				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
16199				if (el.style[prefixedProp] !== undefined) {
16200					return prefixedProp;
16201				}
16202			}
16203		}
16204
16205		// Global support indicators
16206		transform = testProp('transform') || '';
16207		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
16208	}());
16209
16210
16211	/*
16212		PluginDetect v0.7.9
16213		www.pinlady.net/PluginDetect/license/
16214		[ getVersion onWindowLoaded BetterIE ]
16215		[ Flash QuickTime Shockwave ]
16216	*/
16217	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;
16217d++){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);
16217d.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)}
16217c.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;
16217if(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();
16218
16219	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)};
16220
16221
16222	/*
16223		jQuery hashchange event v1.3
16224		https://github.com/cowboy/jquery-hashchange
16225		Copyright (c) 2010 "Cowboy" Ben Alman
16226		Dual licensed under the MIT and GPL licenses.
16227	*/
16228	(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=
16229	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||
16230	"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;
16230a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
16231
16232	if (!Array.prototype.filter) {
16233		Array.prototype.filter = function(fun /*, thisp */ ) {
16234			"use strict";
16235
16236			if (this == null)
16237				throw new TypeError();
16238
16239			var t = Object(this);
16240			var len = t.length >>> 0;
16241			if (typeof fun != "function")
16242				throw new TypeError();
16243
16244			var res = [];
16245			var thisp = arguments[1];
16246			for (var i = 0; i < len; i++) {
16247				if (i in t) {
16248					var val = t[i]; // in case fun mutates this
16249					if (fun.call(thisp, val, i, t))
16250						res.push(val);
16251				}
16252			}
16253
16254			return res;
16255		};
16256	}
16257
16258	if (!Array.prototype.indexOf) {
16259		Array.prototype.indexOf = function(searchElement, fromIndex) {
16260			var k;
16261
16262			if (this == null) {
16263				throw new TypeError('"this" is null or not defined');
16264			}
16265
16266			var O = Object(this);
16267
16268			var len = O.length >>> 0;
16269
16270			if (len === 0) {
16271				return -1;
16272			}
16273
16274			var n = +fromIndex || 0;
16275
16276			if (abs(n) === Infinity) {
16277				n = 0;
16278			}
16279
16280			if (n >= len) {
16281				return -1;
16282			}
16283
16284			k = max(n >= 0 ? n : len - abs(n), 0);
16285
16286			while (k < len) {
16287				var kValue;
16288				if (k in O && O[k] === searchElement) {
16289					return k;
16290				}
16291				k++;
16292			}
16293			return -1;
16294		};
16295	}
16296
16297	if (!Array.prototype.lastIndexOf) {
16298		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
16299			"use strict";
16300
16301			if (this == null)
16302				throw new TypeError();
16303
16304			var t = Object(this);
16305			var len = t.length >>> 0;
16306			if (len === 0)
16307				return -1;
16308
16309			var n = len;
16310			if (arguments.length > 1) {
16311				n = Number(arguments[1]);
16312				if (n != n)
16313					n = 0;
16314				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
16315					n = (n > 0 || -1) * floor(abs(n));
16316			}
16317
16318			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
16319
16320			for (; k >= 0; k--) {
16321				if (k in t && t[k] === searchElement)
16322					return k;
16323			}
16324			return -1;
16325		};
16326	}
16327})(jQuery, this);
16328
16329/**
16330 * Owl carousel
vendor: 31,483 bytes, lines 16331-17534
16331 * @version 2.0.0-beta.3
16332 * @author Bartosz Wojciechowski
16333 * @license The MIT License (MIT)
16334 * @todo Lazy Load Icon
16335 * @todo prevent animationend bubling
16336 * @todo itemsScaleUp
16337 * @todo Test Zepto
16338 * @todo stagePadding calculate wrong active classes
16339 */
16340;(function($, window, document, undefined) {
16341
16342	/**
16343	 * Creates a carousel.
16344	 * @class The Owl Carousel.
16345	 * @public
16346	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
16347	 * @param {Object} [options] - The options
16348	 */
16349	function Owl(element, options) {
16350
16351		/**
16352		 * Current settings for the carousel.
16353		 * @public
16354		 */
16355		this.settings = null;
16356
16357		/**
16358		 * Current options set by the caller including defaults.
16359		 * @public
16360		 */
16361		this.options = $.extend({}, Owl.Defaults, options);
16362
16363		/**
16364		 * Plugin element.
16365		 * @public
16366		 */
16367		this.$element = $(element);
16368
16369		/**
16370		 * Proxied event handlers.
16371		 * @protected
16372		 */
16373		this._handlers = {};
16374
16375		/**
16376		 * References to the running plugins of this carousel.
16377		 * @protected
16378		 */
16379		this._plugins = {};
16380
16381		/**
16382		 * Currently suppressed events to prevent them from beeing retriggered.
16383		 * @protected
16384		 */
16385		this._supress = {};
16386
16387		/**
16388		 * Absolute current position.
16389		 * @protected
16390		 */
16391		this._current = null;
16392
16393		/**
16394		 * Animation speed in milliseconds.
16395		 * @protected
16396		 */
16397		this._speed = null;
16398
16399		/**
16400		 * Coordinates of all items in pixel.
16401		 * @todo The name of this member is missleading.
16402		 * @protected
16403		 */
16404		this._coordinates = [];
16405
16406		/**
16407		 * Current breakpoint.
16408		 * @todo Real media queries would be nice.
16409		 * @protected
16410		 */
16411		this._breakpoint = null;
16412
16413		/**
16414		 * Current width of the plugin element.
16415		 */
16416		this._width = null;
16417
16418		/**
16419		 * All real items.
16420		 * @protected
16421		 */
16422		this._items = [];
16423
16424		/**
16425		 * All cloned items.
16426		 * @protected
16427		 */
16428		this._clones = [];
16429
16430		/**
16431		 * Merge values of all items.
16432		 * @todo Maybe this could be part of a plugin.
16433		 * @protected
16434		 */
16435		this._mergers = [];
16436
16437		/**
16438		 * Widths of all items.
16439		 */
16440		this._widths = [];
16441
16442		/**
16443		 * Invalidated parts within the update process.
16444		 * @protected
16445		 */
16446		this._invalidated = {};
16447
16448		/**
16449		 * Ordered list of workers for the update process.
16450		 * @protected
16451		 */
16452		this._pipe = [];
16453
16454		/**
16455		 * Current state information for the drag operation.
16456		 * @todo #261
16457		 * @protected
16458		 */
16459		this._drag = {
16460			time: null,
16461			target: null,
16462			pointer: null,
16463			stage: {
16464				start: null,
16465				current: null
16466			},
16467			direction: null
16468		};
16469
16470		/**
16471		 * Current state information and their tags.
16472		 * @type {Object}
16473		 * @protected
16474		 */
16475		this._states = {
16476			current: {},
16477			tags: {
16478				'initializing': [ 'busy' ],
16479				'animating': [ 'busy' ],
16480				'dragging': [ 'interacting' ]
16481			}
16482		};
16483
16484		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
16485			this._handlers[handler] = $.proxy(this[handler], this);
16486		}, this));
16487
16488		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
16489			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
16490				= new plugin(this);
16491		}, this));
16492
16493		$.each(Owl.Workers, $.proxy(function(priority, worker) {
16494			this._pipe.push({
16495				'filter': worker.filter,
16496				'run': $.proxy(worker.run, this)
16497			});
16498		}, this));
16499
16500		this.setup();
16501		this.initialize();
16502	}
16503
16504	/**
16505	 * Default options for the carousel.
16506	 * @public
16507	 */
16508	Owl.Defaults = {
16509		items: 3,
16510		loop: false,
16511		center: false,
16512		rewind: false,
16513
16514		mouseDrag: true,
16515		touchDrag: true,
16516		pullDrag: true,
16517		freeDrag: false,
16518
16519		margin: 0,
16520		stagePadding: 0,
16521
16522		merge: false,
16523		mergeFit: true,
16524		autoWidth: false,
16525
16526		startPosition: 0,
16527		rtl: false,
16528
16529		smartSpeed: 250,
16530		fluidSpeed: false,
16531		dragEndSpeed: false,
16532
16533		responsive: {},
16534		responsiveRefreshRate: 200,
16535		responsiveBaseElement: window,
16536
16537		fallbackEasing: 'swing',
16538
16539		info: false,
16540
16541		nestedItemSelector: false,
16542		itemElement: 'div',
16543		stageElement: 'div',
16544
16545		refreshClass: 'owl-refresh',
16546		loadedClass: 'owl-loaded',
16547		loadingClass: 'owl-loading',
16548		rtlClass: 'owl-rtl',
16549		responsiveClass: 'owl-responsive',
16550		dragClass: 'owl-drag',
16551		itemClass: 'owl-item',
16552		stageClass: 'owl-stage',
16553		stageOuterClass: 'owl-stage-outer',
16554		grabClass: 'owl-grab'
16555	};
16556
16557	/**
16558	 * Enumeration for width.
16559	 * @public
16560	 * @readonly
16561	 * @enum {String}
16562	 */
16563	Owl.Width = {
16564		Default: 'default',
16565		Inner: 'inner',
16566		Outer: 'outer'
16567	};
16568
16569	/**
16570	 * Enumeration for types.
16571	 * @public
16572	 * @readonly
16573	 * @enum {String}
16574	 */
16575	Owl.Type = {
16576		Event: 'event',
16577		State: 'state'
16578	};
16579
16580	/**
16581	 * Contains all registered plugins.
16582	 * @public
16583	 */
16584	Owl.Plugins = {};
16585
16586	/**
16587	 * List of workers involved in the update process.
16588	 */
16589	Owl.Workers = [ {
16590		filter: [ 'width', 'settings' ],
16591		run: function() {
16592			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
16593			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
16594		}
16595	}, {
16596		filter: [ 'width', 'items', 'settings' ],
16597		run: function(cache) {
16598			cache.current = this._items && this._items[this.relative(this._current)];
16599		}
16600	}, {
16601		filter: [ 'items', 'settings' ],
16602		run: function() {
16603			this.$stage.children('.cloned').remove();
16604		}
16605	}, {
16606		filter: [ 'width', 'items', 'settings' ],
16607		run: function(cache) {
16608			var margin = this.settings.margin || '',
16609				grid = !this.settings.autoWidth,
16610				rtl = this.settings.rtl,
16611				css = {
16612					'width': 'auto',
16613					'margin-left': rtl ? margin : '',
16614					'margin-right': rtl ? '' : margin
16615				};
16616
16617			!grid && this.$stage.children().css(css);
16618
16619			cache.css = css;
16620		}
16621	}, {
16622		filter: [ 'width', 'items', 'settings' ],
16623		run: function(cache) {
16624			//UNCODE edit to fix Chrome stage padding issue
16625			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
16626				merge = null,
16627				iterator = this._items.length,
16628				grid = !this.settings.autoWidth,
16629				widths = [];
16630
16631			cache.items = {
16632				merge: false,
16633				width: width
16634			};
16635
16636			while (iterator--) {
16637				merge = this._mergers[iterator];
16638				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
16639
16640				cache.items.merge = merge > 1 || cache.items.merge;
16641
16642				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
16643			}
16644
16645			this._widths = widths;
16646		}
16647	}, {
16648		filter: [ 'items', 'settings' ],
16649		run: function() {
16650			var clones = [],
16651				items = this._items,
16652				settings = this.settings,
16653				view = Math.max(settings.items * 2, 4),
16654				size = Math.ceil(items.length / 2) * 2,
16655				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
16656				append = '',
16657				prepend = '';
16658
16659			repeat /= 2;
16660
16661			while (repeat--) {
16662				clones.push(this.normalize(clones.length / 2, true));
16663				append = append + items[clones[clones.length - 1]][0].outerHTML;
16664				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
16665				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
16666			}
16667
16668			this._clones = clones;
16669
16670			// var appendVideo = $(append).find('.uncode-video-container');
16671			// if (appendVideo.length) {
16672			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
16673			// }
16674			// var prependVideo = $(prepend).find('.uncode-video-container');
16675			// if (prependVideo.length) {
16676			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
16677			// }
16678			$(append).addClass('cloned').appendTo(this.$stage);
16679			$(prepend).addClass('cloned').prependTo(this.$stage);
16680		}
16681	}, {
16682		filter: [ 'width', 'items', 'settings' ],
16683		run: function() {
16684			var rtl = this.settings.rtl ? 1 : -1,
16685				size = this._clones.length + this._items.length,
16686				iterator = -1,
16687				previous = 0,
16688				current = 0,
16689				coordinates = [];
16690
16691			while (++iterator < size) {
16692				previous = coordinates[iterator - 1] || 0;
16693				current = this._widths[this.relative(iterator)] + this.settings.margin;
16694				coordinates.push(previous + current * rtl);
16695			}
16696
16697			this._coordinates = coordinates;
16698		}
16699	}, {
16700		filter: [ 'width', 'items', 'settings' ],
16701		run: function() {
16702			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
16703				padding = stagePadding,
16704				coordinates = this._coordinates,
16705				css = {
16706					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
16707					'padding-left': padding || '',
16708					'padding-right': padding || ''
16709				};
16710
16711			this.$stage.css(css);
16712		}
16713	}, {
16714		filter: [ 'width', 'items', 'settings' ],
16715		run: function(cache) {
16716			var iterator = this._coordinates.length,
16717				grid = !this.settings.autoWidth,
16718				items = this.$stage.children();
16719
16720			if (grid && cache.items.merge) {
16721				while (iterator--) {
16722					cache.css.width = this._widths[this.relative(iterator)];
16723					items.eq(iterator).css(cache.css);
16724				}
16725			} else if (grid) {
16726				cache.css.width = cache.items.width;
16727				items.css(cache.css);
16728			}
16729		}
16730	}, {
16731		filter: [ 'items' ],
16732		run: function() {
16733			this._coordinates.length < 1 && this.$stage.removeAttr('style');
16734		}
16735	}, {
16736		filter: [ 'width', 'items', 'settings' ],
16737		run: function(cache) {
16738			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
16739			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
16740			this.reset(cache.current);
16741		}
16742	}, {
16743		filter: [ 'position' ],
16744		run: function() {
16745			this.animate(this.coordinates(this._current));
16746		}
16747	}, {
16748		filter: [ 'width', 'position', 'items', 'settings' ],
16749		run: function() {
16750			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
16751				rtl = this.settings.rtl ? 1 : -1,
16752				padding = this.settings.stagePadding * 2,
16753				begin = this.coordinates(this.current()) + padding,
16754				end = begin + this.width() * rtl,
16755				inner, outer, matches = [], i, n;
16756
16757			for (i = 0, n = this._coordinates.length; i < n; i++) {
16758				inner = this._coordinates[i - 1] || 0;
16759				outer = Math.abs(this._coordinates[i]) + padding * rtl;
16760
16761				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
16762					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
16763					matches.push(i);
16764				}
16765			}
16766
16767			this.$stage.children('.active').removeClass('active');
16768			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
16769
16770			if (this.settings.center) {
16771				this.$stage.children('.center').removeClass('center');
16772				this.$stage.children().eq(this.current()).addClass('center');
16773			}
16774		}
16775	} ];
16776
16777	/**
16778	 * Initializes the carousel.
16779	 * @protected
16780	 */
16781	Owl.prototype.initialize = function() {
16782		this.enter('initializing');
16783		this.trigger('initialize');
16784
16785		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
16786
16787		if (this.settings.autoWidth && !this.is('pre-loading')) {
16788			var imgs, nestedSelector, width;
16789			imgs = this.$element.find('img');
16790			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
16791			width = this.$element.children(nestedSelector).width();
16792
16793			if (imgs.length && width <= 0) {
16794				this.preloadAutoWidthImages(imgs);
16795			}
16796		}
16797
16798		this.$element.addClass(this.options.loadingClass);
16799
16800		// create stage
16801		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
16802			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
16803
16804		// append stage
16805		this.$element.append(this.$stage.parent());
16806
16807		// append content
16808		this.replace(this.$element.children().not(this.$stage.parent()));
16809
16810		// check visibility
16811		if (this.$element.is(':visible')) {
16812			// update view
16813			this.refresh();
16814		} else {
16815			// invalidate width
16816			this.invalidate('width');
16817		}
16818
16819		this.$element
16820			.removeClass(this.options.loadingClass)
16821			.addClass(this.options.loadedClass);
16822
16823		// register event handlers
16824		this.registerEventHandlers();
16825
16826		this.leave('initializing');
16827		this.trigger('initialized');
16828	};
16829
16830	/**
16831	 * Setups the current settings.
16832	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
16833	 * @todo Support for media queries by using `matchMedia` would be nice.
16834	 * @public
16835	 */
16836	Owl.prototype.setup = function() {
16837		var viewport = this.viewport(),
16838			overwrites = this.options.responsive,
16839			match = -1,
16840			settings = null;
16841
16842		if (!overwrites) {
16843			settings = $.extend({}, this.options);
16844		} else {
16845			$.each(overwrites, function(breakpoint) {
16846				if (breakpoint <= viewport && breakpoint > match) {
16847					match = Number(breakpoint);
16848				}
16849			});
16850
16851			settings = $.extend({}, this.options, overwrites[match]);
16852			delete settings.responsive;
16853
16854			// responsive class
16855			if (settings.responsiveClass) {
16856				this.$element.attr('class',
16857					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
16858				);
16859			}
16860		}
16861
16862		if (this.settings === null || this._breakpoint !== match) {
16863			this.trigger('change', { property: { name: 'settings', value: settings } });
16864			this._breakpoint = match;
16865			this.settings = settings;
16866			this.invalidate('settings');
16867			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
16868		}
16869	};
16870
16871	/**
16872	 * Updates option logic if necessery.
16873	 * @protected
16874	 */
16875	Owl.prototype.optionsLogic = function() {
16876		if (this.settings.autoWidth) {
16877			this.settings.stagePadding = false;
16878			this.settings.merge = false;
16879		}
16880	};
16881
16882	/**
16883	 * Prepares an item before add.
16884	 * @todo Rename event parameter `content` to `item`.
16885	 * @protected
16886	 * @returns {jQuery|HTMLElement} - The item container.
16887	 */
16888	Owl.prototype.prepare = function(item, index) {
16889		var event = this.trigger('prepare', { content: item });
16890		if (!event.data) {
16891			event.data = $('<' + this.settings.itemElement + '/>')
16892				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
16893		}
16894
16895		this.trigger('prepared', { content: event.data });
16896
16897		return event.data;
16898	};
16899
16900	/**
16901	 * Updates the view.
16902	 * @public
16903	 */
16904	Owl.prototype.update = function() {
16905		var i = 0,
16906			n = this._pipe.length,
16907			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
16908			cache = {};
16909
16910		while (i < n) {
16911			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
16912				this._pipe[i].run(cache);
16913			}
16914			i++;
16915		}
16916
16917		this._invalidated = {};
16918
16919		!this.is('valid') && this.enter('valid');
16920	};
16921
16922	/**
16923	 * Gets the width of the view.
16924	 * @public
16925	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
16926	 * @returns {Number} - The width of the view in pixel.
16927	 */
16928	Owl.prototype.width = function(dimension) {
16929		dimension = dimension || Owl.Width.Default;
16930		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
16931		switch (dimension) {
16932			case Owl.Width.Inner:
16933			case Owl.Width.Outer:
16934				return this._width;
16935			default:
16936				return this._width - stagePadding * 2 + this.settings.margin;
16937		}
16938	};
16939
16940	/**
16941	 * Refreshes the carousel primarily for adaptive purposes.
16942	 * @public
16943	 */
16944	Owl.prototype.refresh = function() {
16945		this.enter('refreshing');
16946		this.trigger('refresh');
16947
16948		this.setup();
16949
16950		this.optionsLogic();
16951
16952		this.$element.addClass(this.options.refreshClass);
16953
16954		this.update();
16955
16956		this.$element.removeClass(this.options.refreshClass);
16957
16958		this.leave('refreshing');
16959		this.trigger('refreshed');
16960	};
16961
16962	/**
16963	 * Checks window `resize` event.
16964	 * @protected
16965	 */
16966	Owl.prototype.onThrottledResize = function() {
16967		window.clearTimeout(this.resizeTimer);
16968		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
16969	};
16970
16971	/**
16972	 * Checks window `resize` event.
16973	 * @protected
16974	 */
16975	Owl.prototype.onResize = function() {
16976		if (!this._items.length) {
16977			return false;
16978		}
16979
16980		if (this._width === this.$element.width()) {
16981			return false;
16982		}
16983
16984		if (!this.$element.is(':visible')) {
16985			return false;
16986		}
16987
16988		this.enter('resizing');
16989
16990		if (this.trigger('resize').isDefaultPrevented()) {
16991			this.leave('resizing');
16992			return false;
16993		}
16994
16995		this.invalidate('width');
16996
16997		this.refresh();
16998
16999		this.leave('resizing');
17000		this.trigger('resized');
17001	};
17002
17003	/**
17004	 * Registers event handlers.
17005	 * @todo Check `msPointerEnabled`
17006	 * @todo #261
17007	 * @protected
17008	 */
17009	Owl.prototype.registerEventHandlers = function() {
17010		if ($.support.transition) {
17011			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
17012		}
17013
17014		if (this.settings.responsive !== false) {
17015			this.on(window, 'resize', this._handlers.onThrottledResize);
17016		}
17017
17018		if (this.settings.mouseDrag) {
17019			this.$element.addClass(this.options.dragClass);
17020			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
17021			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
17022		}
17023
17024		if (this.settings.touchDrag){
17025			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
17026			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
17027		}
17028	};
17029
17030	/**
17031	 * Handles `touchstart` and `mousedown` events.
17032	 * @todo Horizontal swipe threshold as option
17033	 * @todo #261
17034	 * @protected
17035	 * @param {Event} event - The event arguments.
17036	 */
17037	Owl.prototype.onDragStart = function(event) {
17038		var stage = null;
17039
17040		if (event.which === 3) {
17041			return;
17042		}
17043
17044		if ($.support.transform) {
17045			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
17046			stage = {
17047				x: stage[stage.length === 16 ? 12 : 4],
17048				y: stage[stage.length === 16 ? 13 : 5]
17049			};
17050		} else {
17051			stage = this.$stage.position();
17052			stage = {
17053				x: this.settings.rtl ?
17054					stage.left + this.$stage.width() - this.width() + this.settings.margin :
17055					stage.left,
17056				y: stage.top
17057			};
17058		}
17059
17060		if (this.is('animating')) {
17061			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
17062			this.invalidate('position');
17063		}
17064
17065		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
17066
17067		this.speed(0);
17068
17069		this._drag.time = new Date().getTime();
17070		this._drag.target = $(event.target);
17071		this._drag.stage.start = stage;
17072		this._drag.stage.current = stage;
17073		this._drag.pointer = this.pointer(event);
17074
17075		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
17076
17077		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
17078			var delta = this.difference(this._drag.pointer, this.pointer(event));
17079
17080			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
17081
17082			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
17083				return;
17084			}
17085
17086			event.preventDefault();
17087
17088			this.enter('dragging');
17089			this.trigger('drag');
17090		}, this));
17091	};
17092
17093	/**
17094	 * Handles the `touchmove` and `mousemove` events.
17095	 * @todo #261
17096	 * @protected
17097	 * @param {Event} event - The event arguments.
17098	 */
17099	Owl.prototype.onDragMove = function(event) {
17100		var minimum = null,
17101			maximum = null,
17102			pull = null,
17103			delta = this.difference(this._drag.pointer, this.pointer(event)),
17104			stage = this.difference(this._drag.stage.start, delta);
17105
17106		if (!this.is('dragging')) {
17107			return;
17108		}
17109
17110		event.preventDefault();
17111
17112		if (this.settings.loop) {
17113			minimum = this.coordinates(this.minimum());
17114			maximum = this.coordinates(this.maximum() + 1) - minimum;
17115			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
17116		} else {
17117			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
17118			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
17119			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
17120			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
17121		}
17122
17123		this._drag.stage.current = stage;
17124
17125		this.animate(stage.x);
17126	};
17127
17128	/**
17129	 * Handles the `touchend` and `mouseup` events.
17130	 * @todo #261
17131	 * @todo Threshold for click event
17132	 * @protected
17133	 * @param {Event} event - The event arguments.
17134	 */
17135	Owl.prototype.onDragEnd = function(event) {
17136		var delta = this.difference(this._drag.pointer, this.pointer(event)),
17137			stage = this._drag.stage.current,
17138			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
17139
17140		$(document).off('.owl.core');
17141
17142		this.$element.removeClass(this.options.grabClass);
17143
17144		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
17145			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
17146			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
17147			this.invalidate('position');
17148			this.update();
17149
17150			this._drag.direction = direction;
17151
17152			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
17153				this._drag.target.one('click.owl.core', function() { return false; });
17154			}
17155		}
17156
17157		if (!this.is('dragging')) {
17158			return;
17159		}
17160
17161		this.leave('dragging');
17162		this.trigger('dragged');
17163	};
17164
17165	/**
17166	 * Gets absolute position of the closest item for a coordinate.
17167	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
17168	 * @protected
17169	 * @param {Number} coordinate - The coordinate in pixel.
17170	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
17171	 * @return {Number} - The absolute position of the closest item.
17172	 */
17173	Owl.prototype.closest = function(coordinate, direction) {
17174		var position = -1,
17175			pull = 30,
17176			width = this.width(),
17177			coordinates = this.coordinates();
17178
17179		if (!this.settings.freeDrag) {
17180			// check closest item
17181			$.each(coordinates, $.proxy(function(index, value) {
17182				if (coordinate > value - pull && coordinate < value + pull) {
17183					position = index;
17184				} else if (this.op(coordinate, '<', value)
17185					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
17186					position = direction === 'left' ? index + 1 : index;
17187				}
17188				return position === -1;
17189			}, this));
17190		}
17191
17192		if (!this.settings.loop) {
17193			// non loop boundries
17194			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
17195				position = coordinate = this.minimum();
17196			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
17197				position = coordinate = this.maximum();
17198			}
17199		}
17200
17201		return position;
17202	};
17203
17204	/**
17205	 * Animates the stage.
17206	 * @todo #270
17207	 * @public
17208	 * @param {Number} coordinate - The coordinate in pixels.
17209	 */
17210	Owl.prototype.animate = function(coordinate) {
17211		var animate = this.speed() > 0;
17212
17213		this.is('animating') && this.onTransitionEnd();
17214
17215		if (animate) {
17216			this.enter('animating');
17217			this.trigger('translate');
17218		}
17219
17220		if ($.support.transform3d && $.support.transition) {
17221			this.$stage.css({
17222				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
17223				transition: (this.speed() / 1000) + 's'
17224			});
17225		} else if (animate) {
17226			this.$stage.animate({
17227				left: coordinate + 'px'
17228			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
17229		} else {
17230			this.$stage.css({
17231				left: coordinate + 'px'
17232			});
17233		}
17234	};
17235
17236	/**
17237	 * Checks whether the carousel is in a specific state or not.
17238	 * @param {String} state - The state to check.
17239	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
17240	 */
17241	Owl.prototype.is = function(state) {
17242		return this._states.current[state] && this._states.current[state] > 0;
17243	};
17244
17245	/**
17246	 * Sets the absolute position of the current item.
17247	 * @public
17248	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
17249	 * @returns {Number} - The absolute position of the current item.
17250	 */
17251	Owl.prototype.current = function(position) {
17252		if (position === undefined) {
17253			return this._current;
17254		}
17255
17256		if (this._items.length === 0) {
17257			return undefined;
17258		}
17259
17260		position = this.normalize(position);
17261
17262		if (this._current !== position) {
17263			var event = this.trigger('change', { property: { name: 'position', value: position } });
17264
17265			if (event.data !== undefined) {
17266				position = this.normalize(event.data);
17267			}
17268
17269			this._current = position;
17270
17271			this.invalidate('position');
17272
17273			this.trigger('changed', { property: { name: 'position', value: this._current } });
17274		}
17275
17276		return this._current;
17277	};
17278
17279	/**
17280	 * Invalidates the given part of the update routine.
17281	 * @param {String} [part] - The part to invalidate.
17282	 * @returns {Array.<String>} - The invalidated parts.
17283	 */
17284	Owl.prototype.invalidate = function(part) {
17285		if ($.type(part) === 'string') {
17286			this._invalidated[part] = true;
17287			this.is('valid') && this.leave('valid');
17288		}
17289		return $.map(this._invalidated, function(v, i) { return i });
17290	};
17291
17292	/**
17293	 * Resets the absolute position of the current item.
17294	 * @public
17295	 * @param {Number} position - The absolute position of the new item.
17296	 */
17297	Owl.prototype.reset = function(position) {
17298		position = this.normalize(position);
17299
17300		if (position === undefined) {
17301			return;
17302		}
17303
17304		this._speed = 0;
17305		this._current = position;
17306
17307		this.suppress([ 'translate', 'translated' ]);
17308
17309		this.animate(this.coordinates(position));
17310
17311		this.release([ 'translate', 'translated' ]);
17312	};
17313
17314	/**
17315	 * Normalizes an absolute or a relative position of an item.
17316	 * @public
17317	 * @param {Number} position - The absolute or relative position to normalize.
17318	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
17319	 * @returns {Number} - The normalized position.
17320	 */
17321	Owl.prototype.normalize = function(position, relative) {
17322		var n = this._items.length,
17323			m = relative ? 0 : this._clones.length;
17324
17325		if (!$.isNumeric(position) || n < 1) {
17326			position = undefined;
17327		} else if (position < 0 || position >= n + m) {
17328			position = ((position - m / 2) % n + n) % n + m / 2;
17329		}
17330
17331		return position;
17332	};
17333
17334	/**
17335	 * Converts an absolute position of an item into a relative one.
17336	 * @public
17337	 * @param {Number} position - The absolute position to convert.
17338	 * @returns {Number} - The converted position.
17339	 */
17340	Owl.prototype.relative = function(position) {
17341		position -= this._clones.length / 2;
17342		return this.normalize(position, true);
17343	};
17344
17345	/**
17346	 * Gets the maximum position for the current item.
17347	 * @public
17348	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
17349	 * @returns {Number}
17350	 */
17351	Owl.prototype.maximum = function(relative) {
17352		var settings = this.settings,
17353			maximum = this._coordinates.length,
17354			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
17355			i = -1, j;
17356
17357		if (settings.loop) {
17358			maximum = this._clones.length / 2 + this._items.length - 1;
17359		} else if (settings.autoWidth || settings.merge) {
17360			// binary search
17361			while (maximum - i > 1) {
17362				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
17363					? i = j : maximum = j;
17364			}
17365		} else if (settings.center) {
17366			maximum = this._items.length - 1;
17367		} else {
17368			maximum = this._items.length - settings.items;
17369		}
17370
17371		if (relative) {
17372			maximum -= this._clones.length / 2;
17373		}
17374
17375		return Math.max(maximum, 0);
17376	};
17377
17378	/**
17379	 * Gets the minimum position for the current item.
17380	 * @public
17381	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
17382	 * @returns {Number}
17383	 */
17384	Owl.prototype.minimum = function(relative) {
17385		return relative ? 0 : this._clones.length / 2;
17386	};
17387
17388	/**
17389	 * Gets an item at the specified relative position.
17390	 * @public
17391	 * @param {Number} [position] - The relative position of the item.
17392	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
17393	 */
17394	Owl.prototype.items = function(position) {
17395		if (position === undefined) {
17396			return this._items.slice();
17397		}
17398
17399		position = this.normalize(position, true);
17400		return this._items[position];
17401	};
17402
17403	/**
17404	 * Gets an item at the specified relative position.
17405	 * @public
17406	 * @param {Number} [position] - The relative position of the item.
17407	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
17408	 */
17409	Owl.prototype.mergers = function(position) {
17410		if (position === undefined) {
17411			return this._mergers.slice();
17412		}
17413
17414		position = this.normalize(position, true);
17415		return this._mergers[position];
17416	};
17417
17418	/**
17419	 * Gets the absolute positions of clones for an item.
17420	 * @public
17421	 * @param {Number} [position] - The relative position of the item.
17422	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
17423	 */
17424	Owl.prototype.clones = function(position) {
17425		var odd = this._clones.length / 2,
17426			even = odd + this._items.length,
17427			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
17428
17429		if (position === undefined) {
17430			return $.map(this._clones, function(v, i) { return map(i) });
17431		}
17432
17433		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
17434	};
17435
17436	/**
17437	 * Sets the current animation speed.
17438	 * @public
17439	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
17440	 * @returns {Number} - The current animation speed in milliseconds.
17441	 */
17442	Owl.prototype.speed = function(speed) {
17443		if (speed !== undefined) {
17444			this._speed = speed;
17445		}
17446
17447		return this._speed;
17448	};
17449
17450	/**
17451	 * Gets the coordinate of an item.
17452	 * @todo The name of this method is missleanding.
17453	 * @public
17454	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
17455	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
17456	 */
17457	Owl.prototype.coordinates = function(position) {
17458		var coordinate = null;
17459
17460		if (position === undefined) {
17461			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
17462				return this.coordinates(index);
17463			}, this));
17464		}
17465
17466		if (this.settings.center) {
17467			coordinate = this._coordinates[position];
17468			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
17469		} else {
17470			coordinate = this._coordinates[position - 1] || 0;
17471		}
17472
17473		return coordinate;
17474	};
17475
17476	/**
17477	 * Calculates the speed for a translation.
17478	 * @protected
17479	 * @param {Number} from - The absolute position of the start item.
17480	 * @param {Number} to - The absolute position of the target item.
17481	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
17482	 * @returns {Number} - The time in milliseconds for the translation.
17483	 */
17484	Owl.prototype.duration = function(from, to, factor) {
17485		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
17486	};
17487
17488	/**
17489	 * Slides to the specified item.
17490	 * @public
17491	 * @param {Number} position - The position of the item.
17492	 * @param {Number} [speed] - The time in milliseconds for the transition.
17493	 */
17494	Owl.prototype.to = function(position, speed) {
17495		var current = this.current(),
17496			revert = null,
17497			distance = position - this.relative(current),
17498			direction = (distance > 0) - (distance < 0),
17499			items = this._items.length,
17500			minimum = this.minimum(),
17501			maximum = this.maximum();
17502
17503		if (this.settings.loop) {
17504			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
17505				distance += direction * -1 * items;
17506			}
17507
17508			position = current + distance;
17509			revert = ((position - minimum) % items + items) % items + minimum;
17510
17511			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
17512				current = revert - distance;
17513				position = revert;
17514				this.reset(current);
17515			}
17516		} else if (this.settings.rewind) {
17517			maximum += 1;
17518			position = (position % maximum + maximum) % maximum;
17519		} else {
17520			position = Math.max(minimum, Math.min(maximum, position));
17521		}
17522
17523		this.speed(this.duration(current, position, speed));
17524		this.current(position);
17525
17526		if (this.$element.is(':visible')) {
17527			this.update();
17528		}
17529	};
17530
17531	/**
17532	 * Slides to the next item.
17533	 * @public
17534	 * @param {Number}
vendor: 12,284 bytes, lines 17534-17954
17534 [speed] - The time in milliseconds for the transition.
17535	 */
17536	Owl.prototype.next = function(speed) {
17537		speed = speed || false;
17538		this.to(this.relative(this.current()) + 1, speed);
17539	};
17540
17541	/**
17542	 * Slides to the previous item.
17543	 * @public
17544	 * @param {Number} [speed] - The time in milliseconds for the transition.
17545	 */
17546	Owl.prototype.prev = function(speed) {
17547		speed = speed || false;
17548		this.to(this.relative(this.current()) - 1, speed);
17549	};
17550
17551	/**
17552	 * Handles the end of an animation.
17553	 * @protected
17554	 * @param {Event} event - The event arguments.
17555	 */
17556	Owl.prototype.onTransitionEnd = function(event) {
17557
17558		// if css2 animation then event object is undefined
17559		if (event !== undefined) {
17560			event.stopPropagation();
17561
17562			// Catch only owl-stage transitionEnd event
17563			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
17564				return false;
17565			}
17566		}
17567
17568		this.leave('animating');
17569		this.trigger('translated');
17570	};
17571
17572	/**
17573	 * Gets viewport width.
17574	 * @protected
17575	 * @return {Number} - The width in pixel.
17576	 */
17577	Owl.prototype.viewport = function() {
17578		var width;
17579		if (this.options.responsiveBaseElement !== window) {
17580			width = $(this.options.responsiveBaseElement).width();
17581		} else if (window.innerWidth) {
17582			width = window.innerWidth;
17583		} else if (document.documentElement && document.documentElement.clientWidth) {
17584			width = document.documentElement.clientWidth;
17585		} else {
17586			throw 'Can not detect viewport width.';
17587		}
17588
17589		return width;
17590	};
17591
17592	/**
17593	 * Replaces the current content.
17594	 * @public
17595	 * @param {HTMLElement|jQuery|String} content - The new content.
17596	 */
17597	Owl.prototype.replace = function(content) {
17598		this.$stage.empty();
17599		this._items = [];
17600
17601		if (content) {
17602			content = (content instanceof jQuery) ? content : $(content);
17603		}
17604
17605		if (this.settings.nestedItemSelector) {
17606			content = content.find('.' + this.settings.nestedItemSelector);
17607		}
17608
17609		content.filter(function() {
17610			return this.nodeType === 1;
17611		}).each($.proxy(function(index, item) {
17612			item = this.prepare(item, index);
17613			this.$stage.append(item);
17614			this._items.push(item);
17615			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
17616		}, this));
17617
17618		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
17619
17620		this.invalidate('items');
17621	};
17622
17623	/**
17624	 * Adds an item.
17625	 * @todo Use `item` instead of `content` for the event arguments.
17626	 * @public
17627	 * @param {HTMLElement|jQuery|String} content - The item content to add.
17628	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
17629	 */
17630	Owl.prototype.add = function(content, position) {
17631		var current = this.relative(this._current);
17632
17633		position = position === undefined ? this._items.length : this.normalize(position, true);
17634		content = content instanceof jQuery ? content : $(content);
17635
17636		this.trigger('add', { content: content, position: position });
17637
17638		content = this.prepare(content, this._items[current].index());
17639
17640		if (this._items.length === 0 || position === this._items.length) {
17641			this._items.length === 0 && this.$stage.append(content);
17642			this._items.length !== 0 && this._items[position - 1].after(content);
17643			this._items.push(content);
17644			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
17645		} else {
17646			this._items[position].before(content);
17647			this._items.splice(position, 0, content);
17648			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
17649		}
17650
17651		this._items[current] && this.reset(this._items[current].index());
17652
17653		this.invalidate('items');
17654
17655		this.trigger('added', { content: content, position: position });
17656	};
17657
17658	/**
17659	 * Removes an item by its position.
17660	 * @todo Use `item` instead of `content` for the event arguments.
17661	 * @public
17662	 * @param {Number} position - The relative position of the item to remove.
17663	 */
17664	Owl.prototype.remove = function(position) {
17665		position = this.normalize(position, true);
17666
17667		if (position === undefined) {
17668			return;
17669		}
17670
17671		this.trigger('remove', { content: this._items[position], position: position });
17672
17673		this._items[position].remove();
17674		this._items.splice(position, 1);
17675		this._mergers.splice(position, 1);
17676
17677		this.invalidate('items');
17678
17679		this.trigger('removed', { content: null, position: position });
17680	};
17681
17682	/**
17683	 * Preloads images with auto width.
17684	 * @todo Replace by a more generic approach
17685	 * @protected
17686	 */
17687	Owl.prototype.preloadAutoWidthImages = function(images) {
17688		images.each($.proxy(function(i, element) {
17689			this.enter('pre-loading');
17690			element = $(element);
17691			$(new Image()).one('load', $.proxy(function(e) {
17692				element.attr('src', e.target.src);
17693				element.css('opacity', 1);
17694				this.leave('pre-loading');
17695				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
17696			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
17697		}, this));
17698	};
17699
17700	/**
17701	 * Destroys the carousel.
17702	 * @public
17703	 */
17704	Owl.prototype.destroy = function() {
17705
17706		this.$element.off('.owl.core');
17707		this.$stage.off('.owl.core');
17708		$(document).off('.owl.core');
17709
17710		if (this.settings.responsive !== false) {
17711			window.clearTimeout(this.resizeTimer);
17712			this.off(window, 'resize', this._handlers.onThrottledResize);
17713		}
17714
17715		for (var i in this._plugins) {
17716			this._plugins[i].destroy();
17717		}
17718
17719		this.$stage.children('.cloned').remove();
17720
17721		this.$stage.unwrap();
17722		this.$stage.children().contents().unwrap();
17723		this.$stage.children().unwrap();
17724
17725		this.$element
17726			.removeClass(this.options.refreshClass)
17727			.removeClass(this.options.loadingClass)
17728			.removeClass(this.options.loadedClass)
17729			.removeClass(this.options.rtlClass)
17730			.removeClass(this.options.dragClass)
17731			.removeClass(this.options.grabClass)
17732			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
17733			.removeData('owl.carousel');
17734	};
17735
17736	/**
17737	 * Operators to calculate right-to-left and left-to-right.
17738	 * @protected
17739	 * @param {Number} [a] - The left side operand.
17740	 * @param {String} [o] - The operator.
17741	 * @param {Number} [b] - The right side operand.
17742	 */
17743	Owl.prototype.op = function(a, o, b) {
17744		var rtl = this.settings.rtl;
17745		switch (o) {
17746			case '<':
17747				return rtl ? a > b : a < b;
17748			case '>':
17749				return rtl ? a < b : a > b;
17750			case '>=':
17751				return rtl ? a <= b : a >= b;
17752			case '<=':
17753				return rtl ? a >= b : a <= b;
17754			default:
17755				break;
17756		}
17757	};
17758
17759	/**
17760	 * Attaches to an internal event.
17761	 * @protected
17762	 * @param {HTMLElement} element - The event source.
17763	 * @param {String} event - The event name.
17764	 * @param {Function} listener - The event handler to attach.
17765	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
17766	 */
17767	Owl.prototype.on = function(element, event, listener, capture) {
17768		if (element.addEventListener) {
17769			element.addEventListener(event, listener, capture);
17770		} else if (element.attachEvent) {
17771			element.attachEvent('on' + event, listener);
17772		}
17773	};
17774
17775	/**
17776	 * Detaches from an internal event.
17777	 * @protected
17778	 * @param {HTMLElement} element - The event source.
17779	 * @param {String} event - The event name.
17780	 * @param {Function} listener - The attached event handler to detach.
17781	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
17782	 */
17783	Owl.prototype.off = function(element, event, listener, capture) {
17784		if (element.removeEventListener) {
17785			element.removeEventListener(event, listener, capture);
17786		} else if (element.detachEvent) {
17787			element.detachEvent('on' + event, listener);
17788		}
17789	};
17790
17791	/**
17792	 * Triggers a public event.
17793	 * @todo Remove `status`, `relatedTarget` should be used instead.
17794	 * @protected
17795	 * @param {String} name - The event name.
17796	 * @param {*} [data=null] - The event data.
17797	 * @param {String} [namespace=carousel] - The event namespace.
17798	 * @param {String} [state] - The state which is associated with the event.
17799	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
17800	 * @returns {Event} - The event arguments.
17801	 */
17802	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
17803		var status = {
17804			item: { count: this._items.length, index: this.current() }
17805		}, handler = $.camelCase(
17806			$.grep([ 'on', name, namespace ], function(v) { return v })
17807				.join('-').toLowerCase()
17808		), event = $.Event(
17809			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
17810			$.extend({ relatedTarget: this }, status, data)
17811		);
17812
17813		if (!this._supress[name]) {
17814			$.each(this._plugins, function(name, plugin) {
17815				if (plugin.onTrigger) {
17816					plugin.onTrigger(event);
17817				}
17818			});
17819
17820			this.register({ type: Owl.Type.Event, name: name });
17821			this.$element.trigger(event);
17822
17823			if (this.settings && typeof this.settings[handler] === 'function') {
17824				this.settings[handler].call(this, event);
17825			}
17826		}
17827
17828		return event;
17829	};
17830
17831	/**
17832	 * Enters a state.
17833	 * @param name - The state name.
17834	 */
17835	Owl.prototype.enter = function(name) {
17836		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
17837			if (this._states.current[name] === undefined) {
17838				this._states.current[name] = 0;
17839			}
17840
17841			this._states.current[name]++;
17842		}, this));
17843	};
17844
17845	/**
17846	 * Leaves a state.
17847	 * @param name - The state name.
17848	 */
17849	Owl.prototype.leave = function(name) {
17850		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
17851			this._states.current[name]--;
17852		}, this));
17853	};
17854
17855	/**
17856	 * Registers an event or state.
17857	 * @public
17858	 * @param {Object} object - The event or state to register.
17859	 */
17860	Owl.prototype.register = function(object) {
17861		if (object.type === Owl.Type.Event) {
17862			if (!$.event.special[object.name]) {
17863				$.event.special[object.name] = {};
17864			}
17865
17866			if (!$.event.special[object.name].owl) {
17867				var _default = $.event.special[object.name]._default;
17868				$.event.special[object.name]._default = function(e) {
17869					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
17870						return _default.apply(this, arguments);
17871					}
17872					return e.namespace && e.namespace.indexOf('owl') > -1;
17873				};
17874				$.event.special[object.name].owl = true;
17875			}
17876		} else if (object.type === Owl.Type.State) {
17877			if (!this._states.tags[object.name]) {
17878				this._states.tags[object.name] = object.tags;
17879			} else {
17880				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
17881			}
17882
17883			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
17884				return $.inArray(tag, this._states.tags[object.name]) === i;
17885			}, this));
17886		}
17887	};
17888
17889	/**
17890	 * Suppresses events.
17891	 * @protected
17892	 * @param {Array.<String>} events - The events to suppress.
17893	 */
17894	Owl.prototype.suppress = function(events) {
17895		$.each(events, $.proxy(function(index, event) {
17896			this._supress[event] = true;
17897		}, this));
17898	};
17899
17900	/**
17901	 * Releases suppressed events.
17902	 * @protected
17903	 * @param {Array.<String>} events - The events to release.
17904	 */
17905	Owl.prototype.release = function(events) {
17906		$.each(events, $.proxy(function(index, event) {
17907			delete this._supress[event];
17908		}, this));
17909	};
17910
17911	/**
17912	 * Gets unified pointer coordinates from event.
17913	 * @todo #261
17914	 * @protected
17915	 * @param {Event} - The `mousedown` or `touchstart` event.
17916	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
17917	 */
17918	Owl.prototype.pointer = function(event) {
17919		var result = { x: null, y: null };
17920
17921		event = event.originalEvent || event || window.event;
17922
17923		event = event.touches && event.touches.length ?
17924			event.touches[0] : event.changedTouches && event.changedTouches.length ?
17925				event.changedTouches[0] : event;
17926
17927		if (event.pageX) {
17928			result.x = event.pageX;
17929			result.y = event.pageY;
17930		} else {
17931			result.x = event.clientX;
17932			result.y = event.clientY;
17933		}
17934
17935		return result;
17936	};
17937
17938	/**
17939	 * Gets the difference of two vectors.
17940	 * @todo #261
17941	 * @protected
17942	 * @param {Object} - The first vector.
17943	 * @param {Object} - The second vector.
17944	 * @returns {Object} - The difference.
17945	 */
17946	Owl.prototype.difference = function(first, second) {
17947		return {
17948			x: first.x - second.x,
17949			y: first.y - second.y
17950		};
17951	};
17952
17953	/**
17954	 * The jQuery Plugin for the Owl Carousel
vendor: 32,216 bytes, lines 17955-19237
17955	 * @todo Navigation plugin `next` and `prev`
17956	 * @public
17957	 */
17958	$.fn.owlCarousel = function(option) {
17959		var args = Array.prototype.slice.call(arguments, 1);
17960
17961		return this.each(function() {
17962			var $this = $(this),
17963				data = $this.data('owl.carousel');
17964
17965			if (!data) {
17966				data = new Owl(this, typeof option == 'object' && option);
17967				$this.data('owl.carousel', data);
17968
17969				$.each([
17970					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
17971				], function(i, event) {
17972					data.register({ type: Owl.Type.Event, name: event });
17973					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
17974						if (e.namespace && e.relatedTarget !== this) {
17975							this.suppress([ event ]);
17976							data[event].apply(this, [].slice.call(arguments, 1));
17977							this.release([ event ]);
17978						}
17979					}, data));
17980				});
17981			}
17982
17983			if (typeof option == 'string' && option.charAt(0) !== '_') {
17984				data[option].apply(data, args);
17985			}
17986		});
17987	};
17988
17989	/**
17990	 * The constructor for the jQuery Plugin
17991	 * @public
17992	 */
17993	$.fn.owlCarousel.Constructor = Owl;
17994
17995})(window.Zepto || window.jQuery, window, document);
17996
17997/**
17998 * AutoRefresh Plugin
17999 * @version 2.0.0-beta.3
18000 * @author Artus Kolanowski
18001 * @license The MIT License (MIT)
18002 */
18003;(function($, window, document, undefined) {
18004
18005	/**
18006	 * Creates the auto refresh plugin.
18007	 * @class The Auto Refresh Plugin
18008	 * @param {Owl} carousel - The Owl Carousel
18009	 */
18010	var AutoRefresh = function(carousel) {
18011		/**
18012		 * Reference to the core.
18013		 * @protected
18014		 * @type {Owl}
18015		 */
18016		this._core = carousel;
18017
18018		/**
18019		 * Refresh interval.
18020		 * @protected
18021		 * @type {number}
18022		 */
18023		this._interval = null;
18024
18025		/**
18026		 * Whether the element is currently visible or not.
18027		 * @protected
18028		 * @type {Boolean}
18029		 */
18030		this._visible = null;
18031
18032		/**
18033		 * All event handlers.
18034		 * @protected
18035		 * @type {Object}
18036		 */
18037		this._handlers = {
18038			'initialized.owl.carousel': $.proxy(function(e) {
18039				if (e.namespace && this._core.settings.autoRefresh) {
18040					this.watch();
18041				}
18042			}, this)
18043		};
18044
18045		// set default options
18046		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
18047
18048		// register event handlers
18049		this._core.$element.on(this._handlers);
18050	};
18051
18052	/**
18053	 * Default options.
18054	 * @public
18055	 */
18056	AutoRefresh.Defaults = {
18057		autoRefresh: true,
18058		autoRefreshInterval: 500
18059	};
18060
18061	/**
18062	 * Watches the element.
18063	 */
18064	AutoRefresh.prototype.watch = function() {
18065		if (this._interval) {
18066			return;
18067		}
18068
18069		this._visible = this._core.$element.is(':visible');
18070		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
18071	};
18072
18073	/**
18074	 * Refreshes the element.
18075	 */
18076	AutoRefresh.prototype.refresh = function() {
18077		if (this._core.$element.is(':visible') === this._visible) {
18078			return;
18079		}
18080
18081		this._visible = !this._visible;
18082
18083		this._core.$element.toggleClass('owl-hidden', !this._visible);
18084
18085		this._visible && (this._core.invalidate('width') && this._core.refresh());
18086	};
18087
18088	/**
18089	 * Destroys the plugin.
18090	 */
18091	AutoRefresh.prototype.destroy = function() {
18092		var handler, property;
18093
18094		window.clearInterval(this._interval);
18095
18096		for (handler in this._handlers) {
18097			this._core.$element.off(handler, this._handlers[handler]);
18098		}
18099		for (property in Object.getOwnPropertyNames(this)) {
18100			typeof this[property] != 'function' && (this[property] = null);
18101		}
18102	};
18103
18104	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
18105
18106})(window.Zepto || window.jQuery, window, document);
18107
18108/**
18109 * Lazy Plugin
18110 * @version 2.0.0-beta.3
18111 * @author Bartosz Wojciechowski
18112 * @license The MIT License (MIT)
18113 */
18114;(function($, window, document, undefined) {
18115
18116	/**
18117	 * Creates the lazy plugin.
18118	 * @class The Lazy Plugin
18119	 * @param {Owl} carousel - The Owl Carousel
18120	 */
18121	var Lazy = function(carousel) {
18122
18123		/**
18124		 * Reference to the core.
18125		 * @protected
18126		 * @type {Owl}
18127		 */
18128		this._core = carousel;
18129
18130		/**
18131		 * Already loaded items.
18132		 * @protected
18133		 * @type {Array.<jQuery>}
18134		 */
18135		this._loaded = [];
18136
18137		/**
18138		 * Event handlers.
18139		 * @protected
18140		 * @type {Object}
18141		 */
18142		this._handlers = {
18143			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
18144				if (!e.namespace) {
18145					return;
18146				}
18147
18148				if (!this._core.settings || !this._core.settings.lazyLoad) {
18149					return;
18150				}
18151
18152				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
18153					var settings = this._core.settings,
18154						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
18155						i = ((settings.center && n * -1) || 0),
18156						position = ((e.property && e.property.value) || this._core.current()) + i,
18157						clones = this._core.clones().length,
18158						load = $.proxy(function(i, v) { this.load(v) }, this);
18159
18160					while (i++ < n) {
18161						this.load(clones / 2 + this._core.relative(position));
18162						clones && $.each(this._core.clones(this._core.relative(position)), load);
18163						position++;
18164					}
18165				}
18166			}, this)
18167		};
18168
18169		// set the default options
18170		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
18171
18172		// register event handler
18173		this._core.$element.on(this._handlers);
18174	}
18175
18176	/**
18177	 * Default options.
18178	 * @public
18179	 */
18180	Lazy.Defaults = {
18181		lazyLoad: false
18182	}
18183
18184	/**
18185	 * Loads all resources of an item at the specified position.
18186	 * @param {Number} position - The absolute position of the item.
18187	 * @protected
18188	 */
18189	Lazy.prototype.load = function(position) {
18190		var $item = this._core.$stage.children().eq(position),
18191			$elements = $item && $item.find('.owl-lazy');
18192
18193		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
18194			return;
18195		}
18196
18197		$elements.each($.proxy(function(index, element) {
18198			var $element = $(element), image,
18199				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
18200
18201			this._core.trigger('load', { element: $element, url: url }, 'lazy');
18202
18203			if ($element.is('img')) {
18204				$element.one('load.owl.lazy', $.proxy(function() {
18205					$element.css('opacity', 1);
18206					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
18207				}, this)).attr('src', url);
18208			} else {
18209				image = new Image();
18210				image.onload = $.proxy(function() {
18211					$element.css({
18212						'background-image': 'url(' + url + ')',
18213						'opacity': '1'
18214					});
18215					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
18216				}, this);
18217				image.src = url;
18218			}
18219		}, this));
18220
18221		this._loaded.push($item.get(0));
18222	}
18223
18224	/**
18225	 * Destroys the plugin.
18226	 * @public
18227	 */
18228	Lazy.prototype.destroy = function() {
18229		var handler, property;
18230
18231		for (handler in this.handlers) {
18232			this._core.$element.off(handler, this.handlers[handler]);
18233		}
18234		for (property in Object.getOwnPropertyNames(this)) {
18235			typeof this[property] != 'function' && (this[property] = null);
18236		}
18237	};
18238
18239	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
18240
18241})(window.Zepto || window.jQuery, window, document);
18242
18243/**
18244 * AutoHeight Plugin
18245 * @version 2.0.0-beta.3
18246 * @author Bartosz Wojciechowski
18247 * @license The MIT License (MIT)
18248 */
18249;(function($, window, document, undefined) {
18250
18251	/**
18252	 * Creates the auto height plugin.
18253	 * @class The Auto Height Plugin
18254	 * @param {Owl} carousel - The Owl Carousel
18255	 */
18256	var AutoHeight = function(carousel) {
18257		/**
18258		 * Reference to the core.
18259		 * @protected
18260		 * @type {Owl}
18261		 */
18262		this._core = carousel;
18263
18264		/**
18265		 * All event handlers.
18266		 * @protected
18267		 * @type {Object}
18268		 */
18269		this._handlers = {
18270			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
18271				if (e.namespace && this._core.settings.autoHeight) {
18272					this.update();
18273				}
18274			}, this),
18275			'changed.owl.carousel': $.proxy(function(e) {
18276				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
18277					this.update();
18278				}
18279			}, this),
18280			'loaded.owl.lazy': $.proxy(function(e) {
18281				if (e.namespace && this._core.settings.autoHeight
18282					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
18283					this.update();
18284				}
18285			}, this)
18286		};
18287
18288		// set default options
18289		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
18290
18291		// register event handlers
18292		this._core.$element.on(this._handlers);
18293	};
18294
18295	/**
18296	 * Default options.
18297	 * @public
18298	 */
18299	AutoHeight.Defaults = {
18300		autoHeight: false,
18301		autoHeightClass: 'owl-height'
18302	};
18303
18304	/**
18305	 * Updates the view.
18306	 */
18307	AutoHeight.prototype.update = function() {
18308		var start = this._core._current,
18309			end = start + this._core.settings.items,
18310			visible = this._core.$stage.children().toArray().slice(start, end);
18311			heights = [],
18312			maxheight = 0;
18313
18314		$.each(visible, function(index, item) {
18315			heights.push($(item).height());
18316		});
18317
18318		maxheight = Math.max.apply(null, heights);
18319
18320		this._core.$stage.parent()
18321			.height(maxheight)
18322			.addClass(this._core.settings.autoHeightClass);
18323	};
18324
18325	AutoHeight.prototype.destroy = function() {
18326		var handler, property;
18327
18328		for (handler in this._handlers) {
18329			this._core.$element.off(handler, this._handlers[handler]);
18330		}
18331		for (property in Object.getOwnPropertyNames(this)) {
18332			typeof this[property] != 'function' && (this[property] = null);
18333		}
18334	};
18335
18336	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
18337
18338})(window.Zepto || window.jQuery, window, document);
18339
18340/**
18341 * Video Plugin
18342 * @version 2.0.0-beta.3
18343 * @author Bartosz Wojciechowski
18344 * @license The MIT License (MIT)
18345 */
18346;(function($, window, document, undefined) {
18347
18348	/**
18349	 * Creates the video plugin.
18350	 * @class The Video Plugin
18351	 * @param {Owl} carousel - The Owl Carousel
18352	 */
18353	var Video = function(carousel) {
18354		/**
18355		 * Reference to the core.
18356		 * @protected
18357		 * @type {Owl}
18358		 */
18359		this._core = carousel;
18360
18361		/**
18362		 * Cache all video URLs.
18363		 * @protected
18364		 * @type {Object}
18365		 */
18366		this._videos = {};
18367
18368		/**
18369		 * Current playing item.
18370		 * @protected
18371		 * @type {jQuery}
18372		 */
18373		this._playing = null;
18374
18375		/**
18376		 * All event handlers.
18377		 * @todo The cloned content removale is too late
18378		 * @protected
18379		 * @type {Object}
18380		 */
18381		this._handlers = {
18382			'initialized.owl.carousel': $.proxy(function(e) {
18383				if (e.namespace) {
18384					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
18385				}
18386			}, this),
18387			'resize.owl.carousel': $.proxy(function(e) {
18388				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
18389					e.preventDefault();
18390				}
18391			}, this),
18392			'refreshed.owl.carousel': $.proxy(function(e) {
18393				if (e.namespace && this._core.is('resizing')) {
18394					this._core.$stage.find('.cloned .owl-video-frame').remove();
18395				}
18396			}, this),
18397			'changed.owl.carousel': $.proxy(function(e) {
18398				if (e.namespace && e.property.name === 'position' && this._playing) {
18399					this.stop();
18400				}
18401			}, this),
18402			'prepared.owl.carousel': $.proxy(function(e) {
18403				if (!e.namespace) {
18404					return;
18405				}
18406
18407				var $element = $(e.content).find('.owl-video');
18408
18409				if ($element.length) {
18410					$element.css('display', 'none');
18411					this.fetch($element, $(e.content));
18412				}
18413			}, this)
18414		};
18415
18416		// set default options
18417		this._core.options = $.extend({}, Video.Defaults, this._core.options);
18418
18419		// register event handlers
18420		this._core.$element.on(this._handlers);
18421
18422		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
18423			this.play(e);
18424		}, this));
18425	};
18426
18427	/**
18428	 * Default options.
18429	 * @public
18430	 */
18431	Video.Defaults = {
18432		video: false,
18433		videoHeight: false,
18434		videoWidth: false
18435	};
18436
18437	/**
18438	 * Gets the video ID and the type (YouTube/Vimeo only).
18439	 * @protected
18440	 * @param {jQuery} target - The target containing the video data.
18441	 * @param {jQuery} item - The item containing the video.
18442	 */
18443	Video.prototype.fetch = function(target, item) {
18444		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
18445			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
18446			width = target.attr('data-width') || this._core.settings.videoWidth,
18447			height = target.attr('data-height') || this._core.settings.videoHeight,
18448			url = target.attr('href');
18449
18450		if (url) {
18451			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+)?/);
18452
18453			if (id[3].indexOf('youtu') > -1) {
18454				type = 'youtube';
18455			} else if (id[3].indexOf('vimeo') > -1) {
18456				type = 'vimeo';
18457			} else {
18458				throw new Error('Video URL not supported.');
18459			}
18460			id = id[6];
18461		} else {
18462			throw new Error('Missing video URL.');
18463		}
18464
18465		this._videos[url] = {
18466			type: type,
18467			id: id,
18468			width: width,
18469			height: height
18470		};
18471
18472		item.attr('data-video', url);
18473
18474		this.thumbnail(target, this._videos[url]);
18475	};
18476
18477	/**
18478	 * Creates video thumbnail.
18479	 * @protected
18480	 * @param {jQuery} target - The target containing the video data.
18481	 * @param {Object} info - The video info object.
18482	 * @see `fetch`
18483	 */
18484	Video.prototype.thumbnail = function(target, video) {
18485		var tnLink,
18486			icon,
18487			path,
18488			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
18489			customTn = target.find('img'),
18490			srcType = 'src',
18491			lazyClass = '',
18492			settings = this._core.settings,
18493			create = function(path) {
18494				icon = '<div class="owl-video-play-icon"></div>';
18495
18496				if (settings.lazyLoad) {
18497					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
18498				} else {
18499					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
18500				}
18501				target.after(tnLink);
18502				target.after(icon);
18503			};
18504
18505		// wrap video content into owl-video-wrapper div
18506		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
18507
18508		if (this._core.settings.lazyLoad) {
18509			srcType = 'data-src';
18510			lazyClass = 'owl-lazy';
18511		}
18512
18513		// custom thumbnail
18514		if (customTn.length) {
18515			create(customTn.attr(srcType));
18516			customTn.remove();
18517			return false;
18518		}
18519
18520		if (video.type === 'youtube') {
18521			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
18522			create(path);
18523		} else if (video.type === 'vimeo') {
18524			$.ajax({
18525				type: 'GET',
18526				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
18527				jsonp: 'callback',
18528				dataType: 'jsonp',
18529				success: function(data) {
18530					path = data[0].thumbnail_large;
18531					create(path);
18532				}
18533			});
18534		}
18535	};
18536
18537	/**
18538	 * Stops the current video.
18539	 * @public
18540	 */
18541	Video.prototype.stop = function() {
18542		this._core.trigger('stop', null, 'video');
18543		this._playing.find('.owl-video-frame').remove();
18544		this._playing.removeClass('owl-video-playing');
18545		this._playing = null;
18546		this._core.leave('playing');
18547		this._core.trigger('stopped', null, 'video');
18548	};
18549
18550	/**
18551	 * Starts the current video.
18552	 * @public
18553	 * @param {Event} event - The event arguments.
18554	 */
18555	Video.prototype.play = function(event) {
18556		var target = $(event.target),
18557			item = target.closest('.' + this._core.settings.itemClass),
18558			video = this._videos[item.attr('data-video')],
18559			width = video.width || '100%',
18560			height = video.height || this._core.$stage.height(),
18561			html;
18562
18563		if (this._playing) {
18564			return;
18565		}
18566
18567		this._core.enter('playing');
18568		this._core.trigger('play', null, 'video');
18569
18570		item = this._core.items(this._core.relative(item.index()));
18571
18572		this._core.reset(item.index());
18573
18574		if (video.type === 'youtube') {
18575			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
18576				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
18577		} else if (video.type === 'vimeo') {
18578			html = '<iframe src="//player.vimeo.com/video/' + video.id +
18579				'?autoplay=1" width="' + width + '" height="' + height +
18580				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
18581		}
18582
18583		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
18584
18585		this._playing = item.addClass('owl-video-playing');
18586	};
18587
18588	/**
18589	 * Checks whether an video is currently in full screen mode or not.
18590	 * @todo Bad style because looks like a readonly method but changes members.
18591	 * @protected
18592	 * @returns {Boolean}
18593	 */
18594	Video.prototype.isInFullScreen = function() {
18595		var element = document.fullscreenElement || document.mozFullScreenElement ||
18596				document.webkitFullscreenElement;
18597
18598		return element && $(element).parent().hasClass('owl-video-frame');
18599	};
18600
18601	/**
18602	 * Destroys the plugin.
18603	 */
18604	Video.prototype.destroy = function() {
18605		var handler, property;
18606
18607		this._core.$element.off('click.owl.video');
18608
18609		for (handler in this._handlers) {
18610			this._core.$element.off(handler, this._handlers[handler]);
18611		}
18612		for (property in Object.getOwnPropertyNames(this)) {
18613			typeof this[property] != 'function' && (this[property] = null);
18614		}
18615	};
18616
18617	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
18618
18619})(window.Zepto || window.jQuery, window, document);
18620
18621/**
18622 * Animate Plugin
18623 * @version 2.0.0-beta.3
18624 * @author Bartosz Wojciechowski
18625 * @license The MIT License (MIT)
18626 */
18627;(function($, window, document, undefined) {
18628
18629	/**
18630	 * Creates the animate plugin.
18631	 * @class The Navigation Plugin
18632	 * @param {Owl} scope - The Owl Carousel
18633	 */
18634	var Animate = function(scope) {
18635		this.core = scope;
18636		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
18637		this.swapping = true;
18638		this.previous = undefined;
18639		this.next = undefined;
18640
18641		this.handlers = {
18642			'change.owl.carousel': $.proxy(function(e) {
18643				if (e.namespace && e.property.name == 'position') {
18644					this.previous = this.core.current();
18645					this.next = e.property.value;
18646				}
18647			}, this),
18648			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
18649				if (e.namespace) {
18650					this.swapping = e.type == 'translated';
18651				}
18652			}, this),
18653			'translate.owl.carousel': $.proxy(function(e) {
18654				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
18655					this.swap();
18656				}
18657			}, this)
18658		};
18659
18660		this.core.$element.on(this.handlers);
18661	};
18662
18663	/**
18664	 * Default options.
18665	 * @public
18666	 */
18667	Animate.Defaults = {
18668		animateOut: false,
18669		animateIn: false
18670	};
18671
18672	/**
18673	 * Toggles the animation classes whenever an translations starts.
18674	 * @protected
18675	 * @returns {Boolean|undefined}
18676	 */
18677	Animate.prototype.swap = function() {
18678
18679		if (this.core.settings.items !== 1) {
18680			return;
18681		}
18682
18683		if (!$.support.animation || !$.support.transition) {
18684			return;
18685		}
18686
18687		this.core.speed(0);
18688
18689		var left,
18690			clear = $.proxy(this.clear, this),
18691			previous = this.core.$stage.children().eq(this.previous),
18692			next = this.core.$stage.children().eq(this.next),
18693			incoming = this.core.settings.animateIn,
18694			outgoing = this.core.settings.animateOut;
18695
18696		if (this.core.current() === this.previous) {
18697			return;
18698		}
18699
18700		if (outgoing) {
18701			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
18702			previous.css( { 'left': left + 'px' } )
18703				.addClass('animated owl-animated-out')
18704				.addClass(outgoing)
18705				.on($.support.animation.end, clear);
18706		}
18707
18708		if (incoming) {
18709			next.addClass('animated owl-animated-in')
18710				.addClass(incoming)
18711				.on($.support.animation.end, clear);
18712		}
18713	};
18714
18715	Animate.prototype.clear = function(e) {
18716		if ($(e.target).hasClass('animated')) {
18717			$(e.target).css( { 'left': '' } )
18718				.removeClass('animated owl-animated-out owl-animated-in')
18719				.removeClass(this.core.settings.animateIn)
18720				.removeClass(this.core.settings.animateOut);
18721			this.core.onTransitionEnd();
18722		}
18723	};
18724
18725	/**
18726	 * Destroys the plugin.
18727	 * @public
18728	 */
18729	Animate.prototype.destroy = function() {
18730		var handler, property;
18731
18732		for (handler in this.handlers) {
18733			this.core.$element.off(handler, this.handlers[handler]);
18734		}
18735		for (property in Object.getOwnPropertyNames(this)) {
18736			typeof this[property] != 'function' && (this[property] = null);
18737		}
18738	};
18739
18740	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
18741
18742})(window.Zepto || window.jQuery, window, document);
18743
18744/**
18745 * Autoplay Plugin
18746 * @version 2.0.0-beta.3
18747 * @author Bartosz Wojciechowski
18748 * @author Artus Kolanowski
18749 * @license The MIT License (MIT)
18750 */
18751;(function($, window, document, undefined) {
18752
18753	/**
18754	 * Creates the autoplay plugin.
18755	 * @class The Autoplay Plugin
18756	 * @param {Owl} scope - The Owl Carousel
18757	 */
18758	var Autoplay = function(carousel) {
18759		/**
18760		 * Reference to the core.
18761		 * @protected
18762		 * @type {Owl}
18763		 */
18764		this._core = carousel;
18765
18766		/**
18767		 * The autoplay interval.
18768		 * @type {Number}
18769		 */
18770		this._interval = null;
18771
18772		/**
18773		 * Indicates whenever the autoplay is paused.
18774		 * @type {Boolean}
18775		 */
18776		this._paused = false;
18777
18778		/**
18779		 * All event handlers.
18780		 * @protected
18781		 * @type {Object}
18782		 */
18783		this._handlers = {
18784			'changed.owl.carousel': $.proxy(function(e) {
18785				if (e.namespace && e.property.name === 'settings') {
18786					if (this._core.settings.autoplay) {
18787						this.play();
18788					} else {
18789						this.stop();
18790					}
18791				}
18792			}, this),
18793			'initialized.owl.carousel': $.proxy(function(e) {
18794				if (e.namespace && this._core.settings.autoplay) {
18795					this.play();
18796				}
18797			}, this),
18798			'play.owl.autoplay': $.proxy(function(e, t, s) {
18799				if (e.namespace) {
18800					this.play(t, s);
18801				}
18802			}, this),
18803			'stop.owl.autoplay': $.proxy(function(e) {
18804				if (e.namespace) {
18805					this.stop();
18806				}
18807			}, this),
18808			'mouseover.owl.autoplay': $.proxy(function() {
18809				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
18810					this.pause();
18811				}
18812			}, this),
18813			'mouseleave.owl.autoplay': $.proxy(function() {
18814				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
18815					this.play();
18816				}
18817			}, this)
18818		};
18819
18820		// register event handlers
18821		this._core.$element.on(this._handlers);
18822
18823		// set default options
18824		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
18825	};
18826
18827	/**
18828	 * Default options.
18829	 * @public
18830	 */
18831	Autoplay.Defaults = {
18832		autoplay: false,
18833		autoplayTimeout: 5000,
18834		autoplayHoverPause: false,
18835		autoplaySpeed: false
18836	};
18837
18838	/**
18839	 * Starts the autoplay.
18840	 * @public
18841	 * @param {Number} [timeout] - The interval before the next animation starts.
18842	 * @param {Number} [speed] - The animation speed for the animations.
18843	 */
18844	Autoplay.prototype.play = function(timeout, speed) {
18845		this._paused = false;
18846
18847		if (this._core.is('rotating')) {
18848			return;
18849		}
18850
18851		this._core.enter('rotating');
18852
18853		this._interval = window.setInterval($.proxy(function() {
18854			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
18855				return;
18856			}
18857			this._core.next(speed || this._core.settings.autoplaySpeed);
18858		}, this), timeout || this._core.settings.autoplayTimeout);
18859	};
18860
18861	/**
18862	 * Stops the autoplay.
18863	 * @public
18864	 */
18865	Autoplay.prototype.stop = function() {
18866		if (!this._core.is('rotating')) {
18867			return;
18868		}
18869
18870		window.clearInterval(this._interval);
18871		this._core.leave('rotating');
18872	};
18873
18874	/**
18875	 * Stops the autoplay.
18876	 * @public
18877	 */
18878	Autoplay.prototype.pause = function() {
18879		if (!this._core.is('rotating')) {
18880			return;
18881		}
18882
18883		this._paused = true;
18884	};
18885
18886	/**
18887	 * Destroys the plugin.
18888	 */
18889	Autoplay.prototype.destroy = function() {
18890		var handler, property;
18891
18892		this.stop();
18893
18894		for (handler in this._handlers) {
18895			this._core.$element.off(handler, this._handlers[handler]);
18896		}
18897		for (property in Object.getOwnPropertyNames(this)) {
18898			typeof this[property] != 'function' && (this[property] = null);
18899		}
18900	};
18901
18902	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
18903
18904})(window.Zepto || window.jQuery, window, document);
18905
18906/**
18907 * Navigation Plugin
18908 * @version 2.0.0-beta.3
18909 * @author Artus Kolanowski
18910 * @license The MIT License (MIT)
18911 */
18912;(function($, window, document, undefined) {
18913	'use strict';
18914
18915	/**
18916	 * Creates the navigation plugin.
18917	 * @class The Navigation Plugin
18918	 * @param {Owl} carousel - The Owl Carousel.
18919	 */
18920	var Navigation = function(carousel) {
18921		/**
18922		 * Reference to the core.
18923		 * @protected
18924		 * @type {Owl}
18925		 */
18926		this._core = carousel;
18927
18928		/**
18929		 * Indicates whether the plugin is initialized or not.
18930		 * @protected
18931		 * @type {Boolean}
18932		 */
18933		this._initialized = false;
18934
18935		/**
18936		 * The current paging indexes.
18937		 * @protected
18938		 * @type {Array}
18939		 */
18940		this._pages = [];
18941
18942		/**
18943		 * All DOM elements of the user interface.
18944		 * @protected
18945		 * @type {Object}
18946		 */
18947		this._controls = {};
18948
18949		/**
18950		 * Markup for an indicator.
18951		 * @protected
18952		 * @type {Array.<String>}
18953		 */
18954		this._templates = [];
18955
18956		/**
18957		 * The carousel element.
18958		 * @type {jQuery}
18959		 */
18960		this.$element = this._core.$element;
18961
18962		/**
18963		 * Overridden methods of the carousel.
18964		 * @protected
18965		 * @type {Object}
18966		 */
18967		this._overrides = {
18968			next: this._core.next,
18969			prev: this._core.prev,
18970			to: this._core.to
18971		};
18972
18973		/**
18974		 * All event handlers.
18975		 * @protected
18976		 * @type {Object}
18977		 */
18978		this._handlers = {
18979			'prepared.owl.carousel': $.proxy(function(e) {
18980				if (e.namespace && this._core.settings.dotsData) {
18981					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
18982						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
18983				}
18984			}, this),
18985			'added.owl.carousel': $.proxy(function(e) {
18986				if (e.namespace && this._core.settings.dotsData) {
18987					this._templates.splice(e.position, 0, this._templates.pop());
18988				}
18989			}, this),
18990			'remove.owl.carousel': $.proxy(function(e) {
18991				if (e.namespace && this._core.settings.dotsData) {
18992					this._templates.splice(e.position, 1);
18993				}
18994			}, this),
18995			'changed.owl.carousel': $.proxy(function(e) {
18996				if (e.namespace && e.property.name == 'position') {
18997					this.draw();
18998				}
18999			}, this),
19000			'initialized.owl.carousel': $.proxy(function(e) {
19001				if (e.namespace && !this._initialized) {
19002					this._core.trigger('initialize', null, 'navigation');
19003					this.initialize();
19004					this.update();
19005					this.draw();
19006					this._initialized = true;
19007					this._core.trigger('initialized', null, 'navigation');
19008				}
19009			}, this),
19010			'refreshed.owl.carousel': $.proxy(function(e) {
19011				if (e.namespace && this._initialized) {
19012					this._core.trigger('refresh', null, 'navigation');
19013					this.update();
19014					this.draw();
19015					this._core.trigger('refreshed', null, 'navigation');
19016				}
19017			}, this)
19018		};
19019
19020		// set default options
19021		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
19022
19023		// register event handlers
19024		this.$element.on(this._handlers);
19025	};
19026
19027	/**
19028	 * Default options.
19029	 * @public
19030	 * @todo Rename `slideBy` to `navBy`
19031	 */
19032	Navigation.Defaults = {
19033		nav: false,
19034		navText: [ 'prev', 'next' ],
19035		navSpeed: false,
19036		navElement: 'div',
19037		navContainer: false,
19038		navContainerClass: 'owl-nav',
19039		navClass: [ 'owl-prev', 'owl-next' ],
19040		slideBy: 1,
19041		dotClass: 'owl-dot',
19042		dotsClass: 'owl-dots',
19043		dots: true,
19044		dotsEach: false,
19045		dotsData: false,
19046		dotsSpeed: false,
19047		dotsContainer: false
19048	};
19049
19050	/**
19051	 * Initializes the layout of the plugin and extends the carousel.
19052	 * @protected
19053	 */
19054	Navigation.prototype.initialize = function() {
19055		var override,
19056			settings = this._core.settings;
19057
19058		// create DOM structure for relative navigation
19059		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
19060			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
19061
19062		this._controls.$previous = $('<' + settings.navElement + '>')
19063			.addClass(settings.navClass[0])
19064			.html(settings.navText[0])
19065			.prependTo(this._controls.$relative)
19066			.on('click', $.proxy(function(e) {
19067				this.prev(settings.navSpeed);
19068			}, this));
19069		this._controls.$next = $('<' + settings.navElement + '>')
19070			.addClass(settings.navClass[1])
19071			.html(settings.navText[1])
19072			.appendTo(this._controls.$relative)
19073			.on('click', $.proxy(function(e) {
19074				this.next(settings.navSpeed);
19075			}, this));
19076
19077		// create DOM structure for absolute navigation
19078		if (!settings.dotsData) {
19079			this._templates = [ $('<div>')
19080				.addClass(settings.dotClass)
19081				.append($('<span>'))
19082				.prop('outerHTML') ];
19083		}
19084
19085		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
19086			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
19087
19088		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
19089			var index = $(e.target).parent().is(this._controls.$absolute)
19090				? $(e.target).index() : $(e.target).parent().index();
19091
19092			e.preventDefault();
19093
19094			this.to(index, settings.dotsSpeed);
19095		}, this));
19096
19097		// override public methods of the carousel
19098		for (override in this._overrides) {
19099			this._core[override] = $.proxy(this[override], this);
19100		}
19101	};
19102
19103	/**
19104	 * Destroys the plugin.
19105	 * @protected
19106	 */
19107	Navigation.prototype.destroy = function() {
19108		var handler, control, property, override;
19109
19110		for (handler in this._handlers) {
19111			this.$element.off(handler, this._handlers[handler]);
19112		}
19113		for (control in this._controls) {
19114			this._controls[control].remove();
19115		}
19116		for (override in this.overides) {
19117			this._core[override] = this._overrides[override];
19118		}
19119		for (property in Object.getOwnPropertyNames(this)) {
19120			typeof this[property] != 'function' && (this[property] = null);
19121		}
19122	};
19123
19124	/**
19125	 * Updates the internal state.
19126	 * @protected
19127	 */
19128	Navigation.prototype.update = function() {
19129		var i, j, k,
19130			lower = this._core.clones().length / 2,
19131			upper = lower + this._core.items().length,
19132			maximum = this._core.maximum(true),
19133			settings = this._core.settings,
19134			size = settings.center || settings.autoWidth || settings.dotsData
19135				? 1 : settings.dotsEach || settings.items;
19136
19137		if (settings.slideBy !== 'page') {
19138			settings.slideBy = Math.min(settings.slideBy, settings.items);
19139		}
19140
19141		if (settings.dots || settings.slideBy == 'page') {
19142			this._pages = [];
19143
19144			for (i = lower, j = 0, k = 0; i < upper; i++) {
19145				if (j >= size || j === 0) {
19146					this._pages.push({
19147						start: Math.min(maximum, i - lower),
19148						end: i - lower + size - 1
19149					});
19150					if (Math.min(maximum, i - lower) === maximum) {
19151						break;
19152					}
19153					j = 0, ++k;
19154				}
19155				j += this._core.mergers(this._core.relative(i));
19156			}
19157		}
19158	};
19159
19160	/**
19161	 * Draws the user interface.
19162	 * @todo The option `dotsData` wont work.
19163	 * @protected
19164	 */
19165	Navigation.prototype.draw = function() {
19166		var difference,
19167			settings = this._core.settings,
19168			disabled = this._core.items().length <= settings.items,
19169			index = this._core.relative(this._core.current()),
19170			loop = settings.loop || settings.rewind;
19171
19172		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
19173
19174		if (settings.nav) {
19175			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
19176			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
19177		}
19178
19179		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
19180
19181		if (settings.dots) {
19182			difference = this._pages.length - this._controls.$absolute.children().length;
19183
19184			if (settings.dotsData && difference !== 0) {
19185				this._controls.$absolute.html(this._templates.join(''));
19186			} else if (difference > 0) {
19187				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
19188			} else if (difference < 0) {
19189				this._controls.$absolute.children().slice(difference).remove();
19190			}
19191
19192			this._controls.$absolute.find('.active').removeClass('active');
19193			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
19194		}
19195	};
19196
19197	/**
19198	 * Extends event data.
19199	 * @protected
19200	 * @param {Event} event - The event object which gets thrown.
19201	 */
19202	Navigation.prototype.onTrigger = function(event) {
19203		var settings = this._core.settings;
19204
19205		event.page = {
19206			index: $.inArray(this.current(), this._pages),
19207			count: this._pages.length,
19208			size: settings && (settings.center || settings.autoWidth || settings.dotsData
19209				? 1 : settings.dotsEach || settings.items)
19210		};
19211	};
19212
19213	/**
19214	 * Gets the current page position of the carousel.
19215	 * @protected
19216	 * @returns {Number}
19217	 */
19218	Navigation.prototype.current = function() {
19219		var current = this._core.relative(this._core.current());
19220		return $.grep(this._pages, $.proxy(function(page, index) {
19221			return page.start <= current && page.end >= current;
19222		}, this)).pop();
19223	};
19224
19225	/**
19226	 * Gets the current succesor/predecessor position.
19227	 * @protected
19228	 * @returns {Number}
19229	 */
19230	Navigation.prototype.getPosition = function(successor) {
19231		var position, length,
19232			settings = this._core.settings;
19233
19234		if (settings.slideBy == 'page') {
19235			position = $.inArray(this.current(), this._pages);
19236			length = this._pages.length;
19237			successor ? ++position : --position;
vendor: 5,678 bytes, lines 19238-19462
19238			position = this._pages[((position % length) + length) % length].start;
19239		} else {
19240			position = this._core.relative(this._core.current());
19241			length = this._core.items().length;
19242			successor ? position += settings.slideBy : position -= settings.slideBy;
19243		}
19244
19245		return position;
19246	};
19247
19248	/**
19249	 * Slides to the next item or page.
19250	 * @public
19251	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
19252	 */
19253	Navigation.prototype.next = function(speed) {
19254		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
19255	};
19256
19257	/**
19258	 * Slides to the previous item or page.
19259	 * @public
19260	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
19261	 */
19262	Navigation.prototype.prev = function(speed) {
19263		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
19264	};
19265
19266	/**
19267	 * Slides to the specified item or page.
19268	 * @public
19269	 * @param {Number} position - The position of the item or page.
19270	 * @param {Number} [speed] - The time in milliseconds for the transition.
19271	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
19272	 */
19273	Navigation.prototype.to = function(position, speed, standard) {
19274		var length;
19275
19276		if (!standard) {
19277			length = this._pages.length;
19278			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
19279		} else {
19280			$.proxy(this._overrides.to, this._core)(position, speed);
19281		}
19282	};
19283
19284	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
19285
19286})(window.Zepto || window.jQuery, window, document);
19287
19288/**
19289 * Hash Plugin
19290 * @version 2.0.0-beta.3
19291 * @author Artus Kolanowski
19292 * @license The MIT License (MIT)
19293 */
19294;(function($, window, document, undefined) {
19295	'use strict';
19296
19297	/**
19298	 * Creates the hash plugin.
19299	 * @class The Hash Plugin
19300	 * @param {Owl} carousel - The Owl Carousel
19301	 */
19302	var Hash = function(carousel) {
19303		/**
19304		 * Reference to the core.
19305		 * @protected
19306		 * @type {Owl}
19307		 */
19308		this._core = carousel;
19309
19310		/**
19311		 * Hash index for the items.
19312		 * @protected
19313		 * @type {Object}
19314		 */
19315		this._hashes = {};
19316
19317		/**
19318		 * The carousel element.
19319		 * @type {jQuery}
19320		 */
19321		this.$element = this._core.$element;
19322
19323		/**
19324		 * All event handlers.
19325		 * @protected
19326		 * @type {Object}
19327		 */
19328		this._handlers = {
19329			/*'initialized.owl.carousel': $.proxy(function(e) {
19330				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
19331					$(window).trigger('hashchange.owl.navigation');
19332				}
19333			}, this),*/
19334			'prepared.owl.carousel': $.proxy(function(e) {
19335				if (e.namespace) {
19336					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
19337
19338					if (!hash) {
19339						return;
19340					}
19341
19342					this._hashes[hash] = e.content;
19343				}
19344			}, this),
19345			'changed.owl.carousel': $.proxy(function(e) {
19346				if (e.namespace && e.property.name === 'position') {
19347					var current = this._core.items(this._core.relative(this._core.current())),
19348						hash = $.map(this._hashes, function(item, hash) {
19349							return item === current ? hash : null;
19350						}).join();
19351
19352					if (!hash || window.location.hash.slice(1) === hash) {
19353						return;
19354					}
19355
19356					window.location.hash = hash;
19357				}
19358			}, this)
19359		};
19360
19361		// set default options
19362		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
19363
19364		// register the event handlers
19365		this.$element.on(this._handlers);
19366
19367		// register event listener for hash navigation
19368		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
19369			var hash = window.location.hash.substring(1),
19370				items = this._core.$stage.children(),
19371				position = this._hashes[hash] && items.index(this._hashes[hash]);
19372
19373			if (position === undefined || position === this._core.current()) {
19374				return;
19375			}
19376
19377			this._core.to(this._core.relative(position), false, true);
19378		}, this));*/
19379	};
19380
19381	/**
19382	 * Default options.
19383	 * @public
19384	 */
19385	Hash.Defaults = {
19386		URLhashListener: false
19387	};
19388
19389	/**
19390	 * Destroys the plugin.
19391	 * @public
19392	 */
19393	Hash.prototype.destroy = function() {
19394		var handler, property;
19395
19396		$(window).off('hashchange.owl.navigation');
19397
19398		for (handler in this._handlers) {
19399			this._core.$element.off(handler, this._handlers[handler]);
19400		}
19401		for (property in Object.getOwnPropertyNames(this)) {
19402			typeof this[property] != 'function' && (this[property] = null);
19403		}
19404	};
19405
19406	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
19407
19408})(window.Zepto || window.jQuery, window, document);
19409
19410/**
19411 * Support Plugin
19412 *
19413 * @version 2.0.0-beta.3
19414 * @author Vivid Planet Software GmbH
19415 * @author Artus Kolanowski
19416 * @license The MIT License (MIT)
19417 */
19418;(function($, window, document, undefined) {
19419
19420	var style = $('<support>').get(0).style,
19421		prefixes = 'Webkit Moz O ms'.split(' '),
19422		events = {
19423			transition: {
19424				end: {
19425					WebkitTransition: 'webkitTransitionEnd',
19426					MozTransition: 'transitionend',
19427					OTransition: 'oTransitionEnd',
19428					transition: 'transitionend'
19429				}
19430			},
19431			animation: {
19432				end: {
19433					WebkitAnimation: 'webkitAnimationEnd',
19434					MozAnimation: 'animationend',
19435					OAnimation: 'oAnimationEnd',
19436					animation: 'animationend'
19437				}
19438			}
19439		},
19440		tests = {
19441			csstransforms: function() {
19442				return !!test('transform');
19443			},
19444			csstransforms3d: function() {
19445				return !!test('perspective');
19446			},
19447			csstransitions: function() {
19448				return !!test('transition');
19449			},
19450			cssanimations: function() {
19451				return !!test('animation');
19452			}
19453		};
19454
19455	function test(property, prefixed) {
19456		var result = false,
19457			upper = property.charAt(0).toUpperCase() + property.slice(1);
19458
19459		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
19460			if (style[property] !== undefined) {
19461				result = prefixed ? property : true;
19462				return false;
19463			}
19464		});
19465
19466		return result;
19467	}
19468
19469	function prefixed(property) {
19470		return test(property, true);
19471	}
19472
19473	if (tests.csstransitions()) {
19474		/* jshint -W053 */
19475		$.support.transition = new String(prefixed('transition'))
19476		$.support.transition.end = events.transition.end[ $.support.transition ];
19477	}
19478
19479	if (tests.cssanimations()) {
19480		/* jshint -W053 */
19481		$.support.animation = new String(prefixed('animation'))
19482		$.support.animation.end = events.animation.end[ $.support.animation ];
19483	}
19484
19485	if (tests.csstransforms()) {
19486		/* jshint -W053 */
19487		$.support.transform = new String(prefixed('transform'));
19488		$.support.transform3d = tests.csstransforms3d();
19489	}
19490
19491})(window.Zepto || window.jQuery, window, document);
19492
19493(function(window, document, undefined) {
19494
19495	/**
19496	 * Find the absolute position of an element
19497	 */
19498	var absPos = function(element) {
19499		var offsetLeft, offsetTop;
19500		offsetLeft = offsetTop = 0;
19501		if (element.offsetParent) {
19502			do {
19503				offsetLeft += element.offsetLeft;
19504				offsetTop += element.offsetTop;
19505			} while (element = element.offsetParent);
19506		}
19507		return [offsetLeft, offsetTop];
19508	};
19509
19510	/**
19511	 * @constructor Progress Circle class
19512	 * @param params.canvas Canvas on which the circles will be drawn.
19513	 * @param params.minRadius Inner radius of the innermost circle, in px.
19514	 * @param params.arcWidth Width of each circle(to be more accurate, ring).
19515	 * @param params.gapWidth Space between each circle.
19516	 * @param params.centerX X coordinate of the center of circles.
19517	 * @param params.centerY Y coordinate of the center of circles.
19518	 * @param params.infoLineBaseAngle Base angle of the info line.
19519	 * @param params.infoLineAngleInterval Angles between the info lines.
19520	 */
19521	var ProgressCircle = function(params) {
19522		this.canvas = params.canvas;
19523		this.minRadius = params.minRadius || 15;
19524		this.arcWidth = params.arcWidth || 5;
19525		this.gapWidth = params.gapWidth || 3;
19526		this.centerX = params.centerX || this.canvas.width / 2;
19527		this.centerY = params.centerY || this.canvas.height / 2;
19528		this.infoLineLength = params.infoLineLength || 60;
19529		this.horizLineLength = params.horizLineLength || 10;
19530		this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
19531		this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
19532
19533		this.context = this.canvas.getContext('2d');
19534
19535		this.width = this.canvas.width;
19536		this.height = this.canvas.height;
19537
19538		this.circles = [];
19539		this.runningCount = 0;
19540	};
19541
19542	ProgressCircle.prototype = {
19543		constructor: ProgressCircle,
19544
19545		/**
19546		 * @method Adds an progress monitor entry.
19547		 * @param params.fillColor Color to fill in the circle.
19548		 * @param params.outlineColor Color to outline the circle.
19549		 * @param params.progressListener Callback function to fetch the progress.
19550		 * @param params.infoListener Callback function to fetch the info.
19551		 * @returns this
19552		 */
19553		addEntry: function(params) {
19554			this.circles.push(new Circle({
19555				canvas: this.canvas,
19556				context: this.context,
19557				centerX: this.centerX,
19558				centerY: this.centerY,
19559				innerRadius: this.minRadius + this.circles.length *
19560					(this.gapWidth + this.arcWidth),
19561				arcWidth: this.arcWidth,
19562				infoLineLength: this.infoLineLength,
19563				horizLineLength: this.horizLineLength,
19564
19565				id: this.circles.length,
19566				fillColor: params.fillColor,
19567				outlineColor: params.outlineColor,
19568				progressListener: params.progressListener,
19569				infoListener: params.infoListener,
19570				infoLineAngle: this.infoLineBaseAngle +
19571					this.circles.length * this.infoLineAngleInterval,
19572			}));
19573
19574			return this;
19575		},
19576
19577		/**
19578		 * @method Starts the monitor and updates with the given interval.
19579		 * @param interval Interval between updates, in millisecond.
19580		 * @returns this
19581		 */
19582		start: function(interval) {
19583			var self = this;
19584			this.timer = setInterval(function() {
19585				self._update();
19586			}, interval || 33);
19587
19588			return this;
19589		},
19590
19591		/**
19592		 * @method Stop the animation.
19593		 */
19594		stop: function() {
19595			clearTimeout(this.timer);
19596		},
19597
19598		/**
19599		 * @private
19600		 * @method Call update on each circle and redraw them.
19601		 * @returns this
19602		 */
19603		_update: function() {
19604			this._clear();
19605			this.circles.forEach(function(circle, idx, array) {
19606				circle.update();
19607			});
19608
19609			return this;
19610		},
19611
19612		/**
19613		 * @private
19614		 * @method Clear the canvas.
19615		 * @returns this
19616		 */
19617		_clear: function() {
19618			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
19619
19620			return this;
19621		},
19622
19623	};
19624
19625	/**
19626	 * @private
19627	 * @class Individual progress circle.
19628	 * @param params.canvas Canvas on which the circle will be drawn.
19629	 * @param params.context Context of the canvas.
19630	 * @param params.innerRadius Inner radius of the circle, in px.
19631	 * @param params.arcWidth Width of each arc(circle).
19632	 * @param params.gapWidth Distance between each arc.
19633	 * @param params.centerX X coordinate of the center of circles.
19634	 * @param params.centerY Y coordinate of the center of circles.
19635	 * @param params.fillColor Color to fill in the circle.
19636	 * @param params.outlineColor Color to outline the circle.
19637	 * @param params.progressListener Callback function to fetch the progress.
19638	 * @param params.infoListener Callback function to fetch the info.
19639	 * @param params.infoLineAngle Angle of info line.
19640	 */
19641	var Circle = function(params) {
19642		this.id = params.id;
19643		this.canvas = params.canvas;
19644		this.context = params.context;
19645		this.centerX = params.centerX;
19646		this.centerY = params.centerY;
19647		this.arcWidth = params.arcWidth;
19648		this.innerRadius = params.innerRadius || 0;
19649		this.fillColor = params.fillColor || '#fff';
19650		this.outlineColor = params.outlineColor || this.fillColor;
19651		this.progressListener = params.progressListener;
19652		this.infoLineLength = params.infoLineLength || 250;
19653		this.horizLineLength = params.horizLineLength || 50;
19654		this.infoListener = params.infoListener;
19655		this.infoLineAngle = params.infoLineAngle;
19656
19657		this.outerRadius = this.innerRadius + this.arcWidth;
19658
19659		// If the info listener is not registered, then don't calculate
19660		// the related coordinates
19661		if (!this.infoListener) return;
19662
19663		// calculate the info-line turning points
19664		var angle = this.infoLineAngle,
19665			arcDistance = (this.innerRadius + this.outerRadius) / 2,
19666
19667			sinA = Math.sin(angle),
19668			cosA = Math.cos(angle);
19669
19670		this.infoLineStartX = this.centerX + sinA * arcDistance;
19671		this.infoLineStartY = this.centerY - cosA * arcDistance;
19672
19673		this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
19674		this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
19675
19676		this.infoLineEndX = this.infoLineMidX +
19677			 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
19678		this.infoLineEndY = this.infoLineMidY;
19679
19680		var infoText = document.createElement('div'),
19681			style = infoText.style;
19682
19683		style.color = this.fillColor;
19684		style.position = 'absolute';
19685		style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
19686		// style.top will be calculated in the `drawInfo` method. Since
19687		// user may want to change the size of the font, so the top offset
19688		// must be updated in each loop.
19689		infoText.className = 'ProgressCircleInfo'; // For css styling
19690		infoText.id = 'progress_circle_info_' + this.id;
19691		document.body.appendChild(infoText);
19692		this.infoText = infoText;
19693	};
19694
19695	Circle.prototype = {
19696		constructor: Circle,
19697
19698		update: function() {
19699			this.progress = this.progressListener();
19700			this._draw();
19701
19702			if (this.infoListener) {
19703				this.info = this.infoListener();
19704				this._drawInfo();
19705			}
19706		},
19707
19708		/**
19709		 * @private
19710		 * @method Draw the circle on the canvas.
19711		 * @returns this
19712		 */
19713		_draw: function() {
19714			var ctx = this.context,
19715
19716				ANGLE_OFFSET = -Math.PI / 2,
19717
19718				startAngle = 0 + ANGLE_OFFSET,
19719				endAngle= startAngle + this.progress * Math.PI * 2,
19720
19721				x = this.centerX,
19722				y = this.centerY,
19723
19724				innerRadius = this.innerRadius - this.arcWidth - 1,
19725				outerRadius = this.outerRadius - this.arcWidth - 1;
19726
19727			if ( innerRadius < 0 )
19728				return;
19729
19730			ctx.fillStyle = this.fillColor;
19731			ctx.strokeStyle = this.outlineColor;
19732
19733			ctx.beginPath();
19734			ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
19735			ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
19736			ctx.closePath();
19737			ctx.stroke();
19738			ctx.fill();
19739
19740			return this;
19741		},
19742
19743		/**
19744		 * @private
19745		 * @method Draw the info lines and info text.
19746		 * @returns this
19747		 */
19748		_drawInfo: function() {
19749
19750			var pointList, lineHeight;
19751
19752			pointList = [
19753				[this.infoLineStartX, this.infoLineStartY],
19754				[this.infoLineMidX, this.infoLineMidY],
19755				[this.infoLineEndX, this.infoLineEndY],
19756			];
19757			this._drawSegments(pointList, false);
19758
19759			this.infoText.innerHTML = this.info;
19760
19761			lineHeight = this.infoText.offsetHeight;
19762			this.infoText.style.top = this.infoLineEndY +
19763				absPos(this.canvas)[1] - lineHeight / 2 + 'px';
19764
19765			return this;
19766		},
19767
19768		/**
19769		 * @private
19770		 * @method Helper function to draw the segments
19771		 * @param pointList An array of points in the form of [x, y].
19772		 * @param close Whether to connect the first and last point.
19773		 */
19774		_drawSegments: function(pointList, close) {
19775			var ctx = this.context;
19776
19777			ctx.beginPath();
19778			ctx.moveTo(pointList[0][0], pointList[0][1]);
19779			for (var i = 1; i < pointList.length; ++i) {
19780				ctx.lineTo(pointList[i][0], pointList[i][1]);
19781			}
19782
19783			if (close) {
19784				ctx.closePath();
19785			}
19786			ctx.stroke();
19787		},
19788	};
19789
19790	window.ProgressCircle = ProgressCircle;
19791
19792})(window, document);
19793
19794
19795
19796
19797/* =========================================================
19798 * jquery.vc_chart.js v1.0
19799 * =========================================================
19800 * Copyright 2013 Wpbakery
19801 *
19802 * Jquery chart plugin for the Visual Composer.
19803 * ========================================================= */
19804(function($){
19805	/**
19806	 * Pie chart animated.
19807	 * @param element - DOM element
19808	 * @param options - settings object.
19809	 * @constructor
19810	 */
19811	var VcChart = function(element, options) {
19812		this.el = element;
19813		this.$el = $(this.el);
19814		var $this = this;
19815		$this.options = $.extend({
19816			color: 'wpb_button',
19817			units: '',
19818			width: '',
19819			label_selector: '.vc_pie_chart_value',
19820			back_selector: '.vc_pie_chart_back',
19821			responsive: true
19822		}, options);
19823		$this.init();
19824	};
19825	VcChart.prototype = {
19826		constructor: VcChart,
19827		_progress_v: 0,
19828		animated: false,
19829		colors: {
19830			'wpb_button': 'rgba(247, 247, 247, 1)',
19831			'btn-primary': 'rgba(0, 136, 204, 1)',
19832			'btn-info': 'rgba(88, 185, 218, 1)',
19833			'btn-success': 'rgba(106, 177, 101, 1)',
19834			'btn-warning': 'rgba(255, 153, 0, 1)',
19835			'btn-danger': 'rgba(255, 103, 91, 1)',
19836			'btn-inverse': 'rgba(85, 85, 85, 1)'
19837		},
19838		init: function() {
19839			this.setupColor();
19840			this.value = this.$el.data('pie-value')/100;
19841			this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
19842			this.$wrapper = $('.vc_pie_wrapper', this.$el);
19843			this.$label = $(this.options.label_selector, this.$el);
19844			this.$back = $(this.options.back_selector, this.$el);
19845			this.$canvas = this.$el.find('canvas');
19846			this.arcWidth = this.$el.data('pie-width') * 2;
19847			this.draw();
19848			this.setWayPoint();
19849			if(this.options.responsive === true) this.setResponsive();
19850			if (UNCODE.isMobile) this._progress_v = this.value;
19851		},
19852		setupColor: function() {
19853			// if(typeof this.colors[this.options.color] !== 'undefined') {
19854			//     this.color = this.colors[this.options.color];
19855			// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
19856			//     this.color = this.options.color;
19857			// } else {
19858			//     this.color = 'rgba(247, 247, 247, 0.2)';
19859			// }
19860			if(typeof this.options.color !== 'undefined') {
19861				this.color = this.options.color;
19862			} else this.color = 'rgba(247, 247, 247, 0.2)';
19863
19864		},
19865		setResponsive: function() {
19866			var that = this;
19867			if (!UNCODE.isMobile) {
19868				$(window).resize(function(){
19869					if(that.animated === true) that.circle.stop();
19870					that.draw(true);
19871				});
19872			}
19873		},
19874		draw: function(redraw) {
19875			var w = this.$el.addClass('vc_ready').width() * 2,
19876				border_w = this.arcWidth,
19877				radius;
19878			if(!w) w = this.$el.parents(':visible').first().width()-2;
19879			//w = Math.round(w/100*80);
19880			//if (w < 250) w = 250;
19881			radius = w/2;
19882			this.$wrapper.css({"width" : (w / 2) + "px"});
19883			this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
19884			this.$back.css({"width" : (w / 2), "height" : (w / 2)});
19885			this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
19886			this.$el.addClass('vc_ready');
19887			this.circle = new ProgressCircle({
19888				canvas: this.$canvas.get(0),
19889				minRadius: radius,
19890				arcWidth: border_w
19891			});
19892			if(redraw === true && this.animated === true) {
19893				this._progress_v = this.value;
19894				this.circle.addEntry({
19895					fillColor: this.color,
19896					progressListener: $.proxy(this.setProgress, this)
19897				}).start();
19898			}
19899		},
19900		setProgress: function() {
19901			if (this._progress_v >= this.value) {
19902				this.circle.stop();
19903				this.animated = true;
19904				this.$label.html(this.label_value + this.options.units);
19905				return this._progress_v;
19906			}
19907			this._progress_v += 0.01;
19908			if (!isNaN(this.label_value)) {
19909				var label_value = this._progress_v/this.value*this.label_value;
19910				var val = Math.round(label_value) + this.options.units;
19911				this.$label.html(val);
19912			} else this.$label.html(this.label_value + this.options.units);
19913			return this._progress_v;
19914		},
19915		animate: function() {
19916			if(this.animated !== true) {
19917				this.circle.addEntry({
19918					fillColor: this.color,
19919					progressListener: $.proxy(this.setProgress, this)
19920				}).start(10);
19921			}
19922		},
19923		setWayPoint: function() {
19924			if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
19925				this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
19926			} else {
19927				this.animate();
19928			}
19929		}
19930	};
19931	/**
19932	 * jQuery plugin
19933	 * @param option - object with settings
19934	 * @return {*}
19935	 */
19936	$.fn.vcChat = function(option, value) {
19937		return this.each(function () {
19938			var $this = $(this),
19939				data = $this.data('vc_chart'),
19940				options = typeof option === 'object' ? option : {
19941					color: $this.data('pie-color'),
19942					units: $this.data('pie-units')
19943				};
19944			if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
19945			if (typeof option == 'string') data[option](value);
19946		});
19947	};
19948	/**
19949	 * Allows users to rewrite function inside theme.
19950	 */
19951	if ( typeof window['vc_pieChart'] !== 'function' ) {
19952		window.vc_pieChart = function() {
19953			$('.vc_pie_chart:visible:not(.vc_ready)').vcChat();
19954		}
19955	}
19956	$(document).ready(function(){
19957		!window.vc_iframe && vc_pieChart();
19958
19959		/**
19960		* Tab and collapse integration.
19961		*/
19962		$('.nav-tabs a').on('shown.bs.tab', function(e){
19963			var $cont = $(e.target).closest('.tab-container'),
19964				$active = $('.tab-pane.active', $cont);
19965			$('.vc_pie_chart:not(.vc_ready)', $active).vcChat();
19966		});
19967
19968		$('.panel-collapse').on('shown.bs.collapse', function (e) {
19969			$('.vc_pie_chart:not(.vc_ready)', e.target).vcChat();
19970		})
19971	});
19972
19973})(window.jQuery);
19974
19975/* Progress bar
19976 ---------------------------------------------------------- */
19977function uncode_progress_bar() {
19978	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
19979		if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) {
19980			return;
19981		}
19982		if (!UNCODE.isMobile) {
19983			new Waypoint({
19984				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
19985				element: val,
19986				handler: function() {
19987					var element = jQuery(this.element);
19988					element.find('.vc_single_bar').each(function(index) {
19989						var $this = jQuery(this),
19990							bar = $this.find('.vc_bar'),
19991							val = bar.data('percentage-value');
19992						setTimeout(function() {
19993							bar.css({
19994								"width": val + '%'
19995							});
19996						}, index * 200);
19997					});
19998				},
19999				offset: '80%'
20000			});
20001		} else {
20002			var element = jQuery(val);
20003			element.find('.vc_single_bar').each(function(index) {
20004				var $this = jQuery(this),
20005					bar = $this.find('.vc_bar'),
20006					val = bar.data('percentage-value');
20007				setTimeout(function() {
20008					bar.css({
20009						"width": val + '%'
20010					});
20011				}, index * 200);
20012			});
20013		}
20014	});
20015};
20016uncode_progress_bar();
20017
20018/*!
20019 * jquery.counterup.js 1.0
20020 *
20021 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
20022 * Released under the GPL v2 License
20023 *
20024 * Date: Nov 26, 2013
20025 */
20026(function($) {
20027	"use strict";
20028	$.fn.counterUp = function(options) {
20029		// Defaults
20030		var settings = $.extend({
20031			'time': 400,
20032			'delay': 10
20033		}, options);
20034		return this.each(function() {
20035			// Store the object
20036			var $this = $(this);
20037			var $settings = settings;
20038			var counterUpper = function() {
20039				var nums = [];
20040				var divisions = $settings.time / $settings.delay;
20041				var numReal = $this.attr('data-val'),
20042				num = numReal;
20043				var isComma = /[0-9]+,[0-9]+/.test(num);
20044				num = num.replace(/,/g, '');
20045				var isInt = /^[0-9]+$/.test(num);
20046				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
20047				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
20048				// Generate list of incremental numbers to display
20049				for (var i = divisions; i >= 1; i--) {
20050					// Preserve as int if input was int
20051					var newNum = parseInt(num / divisions * i);
20052					// Preserve float if input was float
20053					if (isFloat) {
20054						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
20055					}
20056					// Preserve commas if input had commas
20057					if (isComma) {
20058						while (/(\d+)(\d{3})/.test(newNum.toString())) {
20059							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
20060						}
20061					}
20062					nums.unshift(newNum);
20063				}
20064				nums.push(numReal);
20065				$this.data('counterup-nums', nums);
20066				$this.text('0');
20067				// Updates the number until we're done
20068				var f = function() {
20069					if ($this.data('counterup-nums') != null) {
20070						$this.text($this.data('counterup-nums').shift());
20071						if ($this.data('counterup-nums').length) {
20072							setTimeout($this.data('counterup-func'), $settings.delay);
20073						} else {
20074							delete $this.data('counterup-nums');
20075							$this.data('counterup-nums', null);
20076							$this.data('counterup-func', null);
20077						}
20078					}
20079				};
20080				$this.data('counterup-func', f);
20081				// Start the count up
20082				setTimeout($this.data('counterup-func'), $settings.delay);
20083			};
20084			// Perform counts when the element gets into view
20085			new Waypoint({
20086				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
20087				element: this,
20088				handler: function() {
20089					counterUpper();
20090					if (!UNCODE.isUnmodalOpen) {
20091						this.destroy();
20092					}
20093				},
20094				offset: '100%'
20095			});
20096		});
20097	};
20098})(jQuery);
20099
20100/*!
20101 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
20102 * Copyright (c) 2016 Edson Hilios
20103 *
20104 * Permission is hereby granted, free of charge, to any person obtaining a copy of
20105 * this software and associated documentation files (the "Software"), to deal in
20106 * the Software without restriction, including without limitation the rights to
20107 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
20108 * the Software, and to permit persons to whom the Software is furnished to do so,
20109 * subject to the following conditions:
20110 *
20111 * The above copyright notice and this permission notice shall be included in all
20112 * copies or substantial portions of the Software.
20113 *
20114 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20115 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20116 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20117 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20118 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20119 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20120 */
20121(function(factory) {
20122	"use strict";
20123	if (typeof define === "function" && define.amd) {
20124		define([ "jquery" ], factory);
20125	} else {
20126		factory(jQuery);
20127	}
20128})(function($) {
20129	"use strict";
20130	var instances = [], matchers = [], defaultOptions = {
20131		precision: 100,
20132		elapse: false,
20133		defer: false
20134	};
20135	matchers.push(/^[0-9]*$/.source);
20136	matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
20137	matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
20138	matchers = new RegExp(matchers.join("|"));
20139	function parseDateString(dateString) {
20140		if (dateString instanceof Date) {
20141			return dateString;
20142		}
20143		if (String(dateString).match(matchers)) {
20144			if (String(dateString).match(/^[0-9]*$/)) {
20145				dateString = Number(dateString);
20146			}
20147			if (String(dateString).match(/\-/)) {
20148				dateString = String(dateString).replace(/\-/g, "/");
20149			}
20150			return new Date(dateString);
20151		} else {
20152			throw new Error("Couldn't cast `" + dateString + "` to a date object.");
20153		}
20154	}
20155	var DIRECTIVE_KEY_MAP = {
20156		Y: "years",
20157		m: "months",
20158		n: "daysToMonth",
20159		d: "daysToWeek",
20160		w: "weeks",
20161		W: "weeksToMonth",
20162		H: "hours",
20163		M: "minutes",
20164		S: "seconds",
20165		D: "totalDays",
20166		I: "totalHours",
20167		N: "totalMinutes",
20168		T: "totalSeconds"
20169	};
20170	function escapedRegExp(str) {
20171		var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
20172		return new RegExp(sanitize);
20173	}
20174	function strftime(offsetObject) {
20175		return function(format) {
20176			var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
20177			if (directives) {
20178				for (var i = 0, len = directives.length; i < len; ++i) {
20179					var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
20180					directive = directive[2];
20181					if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
20182						value = DIRECTIVE_KEY_MAP[directive];
20183						value = Number(offsetObject[value]);
20184					}
20185					if (value !== null) {
20186						if (modifier === "!") {
20187							value = pluralize(plural, value);
20188						}
20189						if (modifier === "") {
20190							if (value < 10) {
20191								value = "0" + value.toString();
20192							}
20193						}
20194						format = format.replace(regexp, value.toString());
20195					}
20196				}
20197			}
20198			format = format.replace(/%%/, "%");
20199			return format;
20200		};
20201	}
20202	function pluralize(format, count) {
20203		var plural = "s", singular = "";
20204		if (format) {
20205			format = format.rep
vendor: 8,618 bytes, lines 20205-20349
20205lace(/(:|;|\s)/gi, "").split(/\,/);
20206			if (format.length === 1) {
20207				plural = format[0];
20208			} else {
20209				singular = format[0];
20210				plural = format[1];
20211			}
20212		}
20213		if (Math.abs(count) > 1) {
20214			return plural;
20215		} else {
20216			return singular;
20217		}
20218	}
20219	var Countdown = function(el, finalDate, options) {
20220		this.el = el;
20221		this.$el = $(el);
20222		this.interval = null;
20223		this.offset = {};
20224		this.options = $.extend({}, defaultOptions);
20225		this.instanceNumber = instances.length;
20226		instances.push(this);
20227		this.$el.data("countdown-instance", this.instanceNumber);
20228		if (options) {
20229			if (typeof options === "function") {
20230				this.$el.on("update.countdown", options);
20231				this.$el.on("stoped.countdown", options);
20232				this.$el.on("finish.countdown", options);
20233			} else {
20234				this.options = $.extend({}, defaultOptions, options);
20235			}
20236		}
20237		this.setFinalDate(finalDate);
20238		if (this.options.defer === false) {
20239			this.start();
20240		}
20241	};
20242	$.extend(Countdown.prototype, {
20243		start: function() {
20244			if (this.interval !== null) {
20245				clearInterval(this.interval);
20246			}
20247			var self = this;
20248			this.update();
20249			this.interval = setInterval(function() {
20250				self.update.call(self);
20251			}, this.options.precision);
20252		},
20253		stop: function() {
20254			clearInterval(this.interval);
20255			this.interval = null;
20256			this.dispatchEvent("stoped");
20257		},
20258		toggle: function() {
20259			if (this.interval) {
20260				this.stop();
20261			} else {
20262				this.start();
20263			}
20264		},
20265		pause: function() {
20266			this.stop();
20267		},
20268		resume: function() {
20269			this.start();
20270		},
20271		remove: function() {
20272			this.stop.call(this);
20273			instances[this.instanceNumber] = null;
20274			delete this.$el.data().countdownInstance;
20275		},
20276		setFinalDate: function(value) {
20277			this.finalDate = parseDateString(value);
20278		},
20279		update: function() {
20280			if (this.$el.closest("html").length === 0) {
20281				this.remove();
20282				return;
20283			}
20284			var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
20285			newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
20286			newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
20287			newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
20288			if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
20289				return;
20290			} else {
20291				this.totalSecsLeft = newTotalSecsLeft;
20292			}
20293			this.elapsed = now >= this.finalDate;
20294			this.offset = {
20295				seconds: this.totalSecsLeft % 60,
20296				minutes: Math.floor(this.totalSecsLeft / 60) % 60,
20297				hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
20298				days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
20299				daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
20300				daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
20301				weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
20302				weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
20303				months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
20304				years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
20305				totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
20306				totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
20307				totalMinutes: Math.floor(this.totalSecsLeft / 60),
20308				totalSeconds: this.totalSecsLeft
20309			};
20310			if (!this.options.elapse && this.totalSecsLeft === 0) {
20311				this.stop();
20312				this.dispatchEvent("finish");
20313			} else {
20314				this.dispatchEvent("update");
20315			}
20316		},
20317		dispatchEvent: function(eventName) {
20318			var event = $.Event(eventName + ".countdown");
20319			event.finalDate = this.finalDate;
20320			event.elapsed = this.elapsed;
20321			event.offset = $.extend({}, this.offset);
20322			event.strftime = strftime(this.offset);
20323			this.$el.trigger(event);
20324		}
20325	});
20326	$.fn.countdown = function() {
20327		var argumentsArray = Array.prototype.slice.call(arguments, 0);
20328		return this.each(function() {
20329			var instanceNumber = $(this).data("countdown-instance");
20330			if (instanceNumber !== undefined) {
20331				var instance = instances[instanceNumber], method = argumentsArray[0];
20332				if (Countdown.prototype.hasOwnProperty(method)) {
20333					instance[method].apply(instance, argumentsArray.slice(1));
20334				} else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
20335					instance.setFinalDate.call(instance, method);
20336					instance.start();
20337				} else {
20338					$.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
20339				}
20340			} else {
20341				new Countdown(this, argumentsArray[0], argumentsArray[1]);
20342			}
20343		});
20344	};
20345});
20346
20347!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;
20348function getStyles(config){
20349  // 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;
20349left: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+"}"
20350};
20351  var ShareUtils;
20352
20353if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
20354  Object.defineProperty(HTMLElement.prototype, "classList", {
20355    get: function() {
20356      var ret, self, update;
20357      update = function(fn) {
20358        return function(value) {
20359          var classes, index;
20360          classes = self.className.split(/\s+/);
20361          index = classes.indexOf(value);
20362          fn(classes, index, value);
20363          self.className = classes.join(" ");
20364        };
20365      };
20366      self = this;
20367      ret = {
20368        add: update(function(classes, index, value) {
20369          ~index || classes.push(value);
20370        }),
20371        remove: update(function(classes, index) {
20372          ~index && classes.splice(index, 1);
20373        }),
20374        toggle: update(function(classes, index, value) {
20375          if (~index) {
20376            classes.splice(index, 1);
20377          } else {
20378            classes.push(value);
20379          }
20380        }),
20381        contains: function(value) {
20382          return !!~self.className.split(/\s+/).indexOf(value);
20383        },
20384        item: function(i) {
20385          return self.className.split(/\s+/)[i] || null;
20386        }
20387      };
20388      Object.defineProperty(ret, "length", {
20389        get: function() {
20390          return self.className.split(/\s+/).length;
20391        }
20392      });
20393      return ret;
20394    }
20395  });
20396}
20397
20398String.prototype.to_rfc3986 = function() {
20399  var tmp;
20400  tmp = encodeURIComponent(this);
20401  return tmp.replace(/[!'()*]/g, function(c) {
20402    return "%" + c.charCodeAt(0).toString(16);
20403  });
20404};
20405
20406ShareUtils = (function() {
20407  function ShareUtils() {}
20408
20409  ShareUtils.prototype.extend = function(to, from, overwrite) {
20410    var hasProp, prop;
20411    for (prop in from) {
20412      hasProp = to[prop] !== undefined;
20413      if (hasProp && typeof from[prop] === "object") {
20414        this.extend(to[prop], from[prop], overwrite);
20415      } else {
20416        if (overwrite || !hasProp) {
20417          to[prop] = from[prop];
20418        }
20419      }
20420    }
20421  };
20422
20423  ShareUtils.prototype.hide = function(el) {
20424    return el.style.display = "none";
20425  };
20426
20427  ShareUtils.prototype.show = function(el) {
20428    return el.style.display = "block";
20429  };
20430
20431  ShareUtils.prototype.has_class = function(el, class_name) {
20432    return el.classList.contains(class_name);
20433  };
20434
20435  ShareUtils.prototype.add_class = function(el, class_name) {
20436    return el.classList.add(class_name);
20437  };
20438
20439  ShareUtils.prototype.remove_class = function(el, class_name) {
20440    return el.classList.remove(class_name);
20441  };
20442
20443  ShareUtils.prototype.is_encoded = function(str) {
20444    str = str.to_rfc3986();
20445    return decodeURIComponent(str) !== str;
20446  };
20447
20448  ShareUtils.prototype.encode = function(str) {
20449    if (typeof str === "undefined" || this.is_encoded(str)) {
20450      return str;
20451    } else {
20452      return str.to_rfc3986();
20453    }
20454  };
20455
20456  ShareUtils.prototype.popup = function(url, params) {
20457    var k, popup, qs, v;
20458    if (params == null) {
20459      params = {};
20460    }
20461    popup = {
20462      width: 500,
20463      height: 350
20464    };
20465    popup.top = (screen.height / 2) - (popup.height / 2);
20466    popup.left = (screen.width / 2) - (popup.width / 2);
20467    qs = ((function() {
20468      var _results;
20469      _results = [];
20470      for (k in params) {
20471        v = params[k];
20472        _results.push("" + k + "=" + (this.encode(v)));
20473      }
20474      return _results;
20475    }).call(this)).join('&');
20476    if (qs) {
20477      qs = "?" + qs;
20478    }
20479    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=" 
20479+ popup.width + ",height=" + popup.height);
20480  };
20481
20482  return ShareUtils;
20483
20484})();
20485var Share,
20486  __hasProp = {}.hasOwnProperty,
20487  __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; };
20488
20489Share = (function(_super) {
20490  __extends(Share, _super);
20491
20492  function Share(element, options) {
20493    this.element = element;
20494    this.el = {
20495      head: document.getElementsByTagName('head')[0],
20496      body: document.getElementsByTagName('body')[0]
20497    };
20498    this.config = {
20499      enabled_networks: 0,
20500      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
20501      url: window.location.href.replace("&", "%26"),
20502      caption: null,
20503      title: this.default_title(),
20504      image: this.default_image(),
20505      description: this.default_description(),
20506      ui: {
20507        flyout: 'top center',
20508        button_text: 'Share',
20509        button_font: true,
20510        icon_font: true
20511      },
20512      networks: {
20513        twitter: {
20514          enabled: true,
20515          url: null,
20516          title: null,
20517          description: null
20518        },
20519        facebook: {
20520          enabled: true,
20521          load_sdk: true,
20522          url: null,
20523          app_id: null,
20524          title: null,
20525          caption: null,
20526          description: null,
20527          image: null
20528        },
20529        pinterest: {
20530          enabled: true,
20531          url: null,
20532          image: null,
20533          description: null
20534        },
20535        reddit: {
20536          enabled: true,
20537          url: null,
20538          title: null
20539        },
20540        linkedin: {
20541          enabled: true,
20542          url: null,
20543          title: null,
20544          description: null
20545        },
20546        xing: {
20547          enabled: true,
20548          url: null,
20549          title: null,
20550          image: null,
20551          description: null
20552        },
20553        whatsapp: {
20554          enabled: true,
20555          description: null,
20556          url: null
20557        },
20558        email: {
20559          enabled: true,
20560          title: null,
20561          description: null,
20562          url: null
20563        }
20564      }
20565    };
20566    this.setup(element, options);
20567    return this;
20568  }
20569
20570  Share.prototype.setup = function(element, opts) {
20571    var index, instance, instances, _i, _len;
20572    instances = document.querySelectorAll(element);
20573    this.extend(this.config, opts, true);
20574    this.set_global_configuration();
20575    this.normalize_network_configuration();
20576    if (this.config.ui.icon_font) {
20577      this.inject_icons();
20578    }
20579    if (this.config.ui.button_font) {
20580      this.inject_fonts();
20581    }
20582    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
20583      this.inject_facebook_sdk();
20584    }
20585    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
20586      instance = instances[index];
20587      this.setup_instance(element, index);
20588    }
20589  };
20590
20591  Share.prototype.setup_instance = function(element, index) {
20592    var button, instance, label, network, networks, _i, _len, _results,
20593      _this = this;
20594    instance = document.querySelectorAll(element)[index];
20595    this.hide(instance);
20596    this.add_class(instance, "sharer-" + index);
20597    instance = document.querySelectorAll(element)[index];
20598    this.inject_css(instance);
20599    this.inject_html(instance);
20600    this.show(instance);
20601    label = instance.getElementsByTagName("label")[0];
20602    button = instance.getElementsByClassName("social")[0];
20603    networks = instance.getElementsByTagName('li');
20604    this.add_class(button, "networks-" + this.config.enabled_networks);
20605    label.addEventListener("click", function() {
20606      return _this.event_toggle(button);
20607    });
20608    _this = this;
20609    _results = [];
20610    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
20611      network = networks[index];
20612      _results.push(network.addEventListener("click", function() {
20613        _this.event_network(instance, this);
20614        return _this.event_close(button);
20615      }));
20616    }
20617    return _results;
20618  };
20619
20620  Share.prototype.event_toggle = function(button) {
20621    if (this.has_class(button, "active")) {
20622      return this.event_close(button);
20623    } else {
20624      return this.event_open(button);
20625    }
20626  };
20627
20628  Share.prototype.event_open = function(button) {
20629    if (this.has_class(button, "load")) {
20630      this.remove_class(button, "load");
20631    }
20632    return this.add_class(button, "active");
20633  };
20634
20635  Share.prototype.event_close = function(button) {
20636    return this.remove_class(button, "active");
20637  };
20638
20639  Share.prototype.event_network = function(instance, network) {
20640    var name;
20641    name = network.getAttribute("data-network");
20642    this.hook("before", name, instance);
20643    this["network_" + name]();
20644    return this.hook("after", name, instance);
20645  };
20646
20647  Share.prototype.open = function() {
20648    return this["public"]("open");
20649  };
20650
20651  Share.prototype.close = function() {
20652    return this["public"]("close");
20653  };
20654
20655  Share.prototype.toggle = function() {
20656    return this["public"]("toggle");
20657  };
20658
20659  Share.prototype["public"] = function(action) {
20660    var button, index, instance, _i, _len, _ref, _results;
20661    _ref = document.querySelectorAll(this.element);
20662    _results = [];
20663    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
20664      instance = _ref[index];
20665      button = instance.getElementsByClassName("social")[0];
20666      _results.push(this["event_" + action](button));
20667    }
20668    return _results;
20669  };
20670
20671  Share.prototype.network_facebook = function() {
20672    if (this.config.networks.facebook.load_sdk) {
20673      if (!window.FB) {
20674        return console.error("The Facebook JS SDK hasn't loaded yet.");
20675      }
20676      return FB.ui({
20677        method: 'feed',
20678        name: this.config.networks.facebook.title,
20679        link: this.config.networks.facebook.url,
20680        picture: this.config.networks.facebook.image,
20681        caption: this.config.networks.facebook.caption,
20682        description: this.config.networks.facebook.description
20683      });
20684    } else {
20685      return this.popup('https://www.facebook.com/sharer/sharer.php', {
20686        u: this.config.networks.facebook.url
20687      });
20688    }
20689  };
20690
20691  Share.prototype.network_twitter = function() {
20692    return this.popup('https://twitter.com/intent/tweet', {
20693      text: this.config.networks.twitter.title,
20694      url: this.config.networks.twitter.url
20695    });
20696  };
20697
20698  Share.prototype.network_pinterest = function() {
20699    return this.popup('https://www.pinterest.com/pin/create/button', {
20700      url: this.config.networks.pinterest.url,
20701      media: this.config.networks.pinterest.image,
20702      description: this.config.networks.pinterest.description
20703    });
20704  };
20705
20706  Share.prototype.network_linkedin = function() {
20707    return this.popup('https://www.linkedin.com/shareArticle', {
20708      url: this.config.networks.linkedin.url,
20709      title: this.config.networks.linkedin.title,
20710      summary: this.config.networks.linkedin.description
20711    });
20712  }
20713
20714  Share.prototype.network_xing = function() {
20715    return this.popup('https://www.xing.com/spi/shares/new', {
20716      url: this.config.networks.xing.url,
20717      image: this.config.networks.xing.image,
20718      title: this.config.networks.xing.title,
20719      summary: this.config.networks.xing.description
20720    });
20721  }
20722
20723  Share.prototype.network_email = function() {
20724    return this.popup('mailto:', {
20725      subject: this.config.networks.email.title,
20726      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
20727    });
20728  };
20729
20730  Share.prototype.inject_icons = function() {
20731  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
20732  };
20733
20734  Share.prototype.inject_fonts = function() {
20735   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
20736  };
20737
20738  Share.prototype.inject_stylesheet = function(url) {
20739    var link;
20740    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
20741      link = document.createElement("link");
20742      link.setAttribute("rel", "stylesheet");
20743      link.setAttribute("href", url);
20744      return this.el.head.appendChild(link);
20745    }
20746  };
20747
20748  Share.prototype.inject_css = function(instance) {
20749    var css, meta, selector, style;
20750    selector = "." + (instance.getAttribute('class').split(" ").join("."));
20751    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
20752      this.config.selector = selector;
20753      css = getStyles(this.config);
20754      style = document.createElement("style");
20755      style.type = "text/css";
20756      if (style.styleSheet) {
20757        style.styleSheet.cssText = css;
20758      } else {
20759        style.appendChild(document.createTextNode(css));
20760      }
20761      this.el.head.appendChild(style);
20762      delete this.config.selector;
20763      meta = document.createElement("meta");
20764      meta.setAttribute("name", "sharer" + selector);
20765      return this.el.head.appendChild(meta);
20766    }
20767  };
20768
20769  Share.prototype.inject_html = function(instance) {
20770    //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>";
20771    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-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>";
20772  };
20773
20774  Share.prototype.inject_facebook_sdk = function() {
20775    var fb_root, script;
20776    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
20777      script = document.createElement("script");
20778      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')";
20779      fb_root = document.createElement("div");
20780      fb_root.id = "fb-root";
20781      this.el.body.appendChild(fb_root);
20782      return this.el.body.appendChild(script);
20783    }
20784  };
20785
20786  Share.prototype.hook = function(type, network, instance) {
20787    var fn, opts;
20788    fn = this.config.networks[network][type];
20789    if (typeof fn === "function") {
20790      opts = fn.call(this.config.networks[network], instance);
20791      if (opts !== void 0) {
20792        opts = this.normalize_filter_config_updates(opts);
20793        this.extend(this.config.networks[network], opts, true);
20794        this.normalize_network_configuration();
20795      }
20796    }
20797  };
20798
20799  Share.prototype.default_title = function() {
20800    var content;
20801    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
20802      return encodeURIComponent(content.getAttribute('content'));
20803    } else if (content = document.querySelector('title')) {
20804      return encodeURIComponent(content.innerText);
20805    }
20806  };
20807
20808  Share.prototype.default_image = function() {
20809    var content;
20810    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
20811      return content.getAttribute('content');
20812    }
20813  };
20814
20815  Share.prototype.default_description = function() {
20816    var content;
20817    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
20818      return encodeURIComponent(content.getAttribute('content'));
20819    } else {
20820      return '';
20821    }
20822  };
20823
20824  Share.prototype.set_global_configuration = function() {
20825    var display, network, option, options, _ref, _results;
20826    _ref = this.config.networks;
20827    _results = [];
20828    for (network in _ref) {
20829      options = _ref[network];
20830      for (option in options) {
20831        if (this.config.networks[network][option] == null) {
20832          this.config.networks[network][option] = this.config[option];
20833        }
20834      }
20835      if (this.config.networks[network].enabled) {
20836        display = 'block';
20837        this.config.enabled_networks += 1;
20838      } else {
20839        display = 'none';
20840      }
20841      _results.push(this.config.networks[network].display = display);
20842    }
20843    return _results;
20844  };
20845
20846  Share.prototype.normalize_network_configuration = function() {
20847    if (!this.config.networks.facebook.app_id) {
20848      this.config.networks.facebook.load_sdk = false;
20849    }
20850    if (!this.is_encoded(this.config.networks.twitter.description)) {
20851      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
20852    }
20853    if (typeof this.config.networks.facebook.app_id === 'number') {
20854      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
20855    }
20856  };
20857
20858  Share.prototype.normalize_filter_config_updates = function(opts) {
20859    if (this.config.networks.facebook.app_id !== opts.app_id) {
20860      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.");
20861      delete opts.app_id;
20862    }
20863    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
20864      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.");
20865      delete opts.app_id;
20866    }
20867    return opts;
20868  };
20869
20870  return Share;
20871
20872})(ShareUtils);
20873 return Share;
20874});
20875
20876// Generated by CoffeeScript 1.9.2
20877
20878// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
20879
20880(function() {
20881  var $, win;
20882
20883  $ = this.jQuery || window.jQuery;
20884
20885  win = $(window);
20886
20887  $.fn.stick_in_parent = function(opts) {
20888    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
20889    if (opts == null) {
20890      opts = {};
20891    }
20892    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;
20893    if (offset_top == null) {
20894      offset_top = 0;
20895    }
20896    if (parent_selector == null) {
20897      parent_selector = void 0;
20898    }
20899    if (inner_scrolling == null) {
20900      inner_scrolling = true;
20901    }
20902    if (sticky_class == null) {
20903      sticky_class = "is_stuck";
20904    }
20905    doc = $(document);
20906    if (enable_bottoming == null) {
20907      enable_bottoming = true;
20908    }
20909    outer_width = function(el) {
20910      var _el, computed, w;
20911      if (window.getComputedStyle) {
20912        _el = el[0];
20913        computed = window.getComputedStyle(el[0]);
20914        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
20915        if (computed.getPropertyValue("box-sizing") !== "border-box") {
20916          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
20917        }
20918        return w;
20919      } else {
20920        return el.outerWidth(true);
20921      }
20922    };
20923    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
20924      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
20925      if (elm.data("sticky_kit")) {
20926        return;
20927      }
20928      elm.data("sticky_kit", true);
20929      last_scroll_height = doc.height();
20930      parent = elm.parent();
20931      if (parent_selector != null) {
20932        parent = parent.closest(parent_selector);
20933      }
20934      if (!parent.length) {
20935        throw "failed to find stick parent";
20936      }
20937      fixed = false;
20938      bottomed = false;
20939      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
20940      if (spacer) {
20941        spacer.css('position', elm.css('position'));
20942      }
20943      recalc = function() {
20944        var border_top, padding_top, restore;
20945        if (detached) {
20946          return;
20947        }
20948        last_scroll_height = doc.height();
20949        border_top = parseInt(parent.css("border-top-width"), 10);
20950        padding_top = parseInt(parent.css("padding-top"), 10);
20951        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
20952        parent_top = parent.offset().top + border_top + padding_top;
20953        parent_height = parent.height();
20954        if (fixed) {
20955          fixed = false;
vendor: 6,068 bytes, lines 20956-21150
20956          bottomed = false;
20957          if (manual_spacer == null) {
20958            elm.insertAfter(spacer);
20959            spacer.detach();
20960          }
20961          elm.css({
20962            position: "",
20963            top: "",
20964            width: "",
20965            bottom: ""
20966          }).removeClass(sticky_class);
20967          restore = true;
20968        }
20969        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
20970        height = elm.outerHeight(true);
20971        el_float = elm.css("float");
20972        if (spacer) {
20973          spacer.css({
20974            width: outer_width(elm),
20975            height: height,
20976            display: elm.css("display"),
20977            "vertical-align": elm.css("vertical-align"),
20978            "float": el_float
20979          });
20980        }
20981        if (restore) {
20982          return tick();
20983        }
20984      };
20985      recalc();
20986      if (height === parent_height) {
20987        return;
20988      }
20989      last_pos = void 0;
20990      offset = offset_top;
20991      recalc_counter = recalc_every;
20992      tick = function() {
20993        var css, delta, recalced, scroll, will_bottom, win_height;
20994        if (detached) {
20995          return;
20996        }
20997        recalced = false;
20998        if (recalc_counter != null) {
20999          recalc_counter -= 1;
21000          if (recalc_counter <= 0) {
21001            recalc_counter = recalc_every;
21002            recalc();
21003            recalced = true;
21004          }
21005        }
21006        if (!recalced && doc.height() !== last_scroll_height) {
21007          recalc();
21008          recalced = true;
21009        }
21010        scroll = win.scrollTop();
21011        if (last_pos != null) {
21012          delta = scroll - last_pos;
21013        }
21014        last_pos = scroll;
21015        if (fixed) {
21016          if (enable_bottoming) {
21017            will_bottom = scroll + height + offset > parent_height + parent_top;
21018            if (bottomed && !will_bottom) {
21019              bottomed = false;
21020              elm.css({
21021                position: "fixed",
21022                bottom: "",
21023                top: offset
21024              }).trigger("sticky_kit:unbottom");
21025            }
21026          }
21027          if (scroll < top) {
21028            fixed = false;
21029            offset = offset_top;
21030            if (manual_spacer == null) {
21031              if (el_float === "left" || el_float === "right") {
21032                elm.insertAfter(spacer);
21033              }
21034              spacer.detach();
21035            }
21036            css = {
21037              position: "",
21038              width: "",
21039              top: ""
21040            };
21041            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
21042          }
21043          if (inner_scrolling) {
21044            win_height = win.height();
21045            if (height + offset_top > win_height) {
21046              if (!bottomed) {
21047                offset -= delta;
21048                offset = Math.max(win_height - height, offset);
21049                offset = Math.min(offset_top, offset);
21050                if (fixed) {
21051                  elm.css({
21052                    top: offset + "px"
21053                  });
21054                }
21055              }
21056            }
21057          }
21058        } else {
21059          if (scroll > top) {
21060            fixed = true;
21061            css = {
21062              position: "fixed",
21063              top: offset
21064            };
21065            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
21066            elm.css(css).addClass(sticky_class);
21067            if (manual_spacer == null) {
21068              elm.after(spacer);
21069              if (el_float === "left" || el_float === "right") {
21070                spacer.append(elm);
21071              }
21072            }
21073            elm.trigger("sticky_kit:stick");
21074          }
21075        }
21076        if (fixed && enable_bottoming) {
21077          if (will_bottom == null) {
21078            will_bottom = scroll + height + offset > parent_height + parent_top;
21079          }
21080          if (!bottomed && will_bottom) {
21081            bottomed = true;
21082            if (parent.css("position") === "static") {
21083              parent.css({
21084                position: "relative"
21085              });
21086            }
21087            return elm.css({
21088              position: "absolute",
21089              bottom: padding_bottom,
21090              top: "auto"
21091            }).trigger("sticky_kit:bottom");
21092          }
21093        }
21094      };
21095      recalc_and_tick = function() {
21096        recalc();
21097        return tick();
21098      };
21099      detach = function() {
21100        detached = true;
21101        win.off("touchmove", tick);
21102        win.off("scroll", tick);
21103        win.off("resize", recalc_and_tick);
21104        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
21105        elm.off("sticky_kit:detach", detach);
21106        elm.removeData("sticky_kit");
21107        elm.css({
21108          position: "",
21109          bottom: "",
21110          top: "",
21111          width: ""
21112        });
21113        parent.position("position", "");
21114        if (fixed) {
21115          if (manual_spacer == null) {
21116            if (el_float === "left" || el_float === "right") {
21117              elm.insertAfter(spacer);
21118            }
21119            spacer.remove();
21120          }
21121          return elm.removeClass(sticky_class);
21122        }
21123      };
21124      win.on("touchmove", tick);
21125      win.on("scroll", tick);
21126      win.on("resize", recalc_and_tick);
21127      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
21128      elm.on("sticky_kit:detach", detach);
21129      return setTimeout(tick, 0);
21130    };
21131    for (i = 0, len = this.length; i < len; i++) {
21132      elm = this[i];
21133      fn($(elm));
21134    }
21135    return this;
21136  };
21137
21138}).call(this);
21139/* ==========================================================================
21140 * bootstrap-tab-history.js
21141 * Author: Michael Narayan <[email protected]>
21142 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
21143 * ==========================================================================
21144 * Licensed under the Apache License, Version 2.0 (the "License"); you may
21145 * not use this file except in compliance with the License. You may obtain a
21146 * copy of the License at
21147 *
21148 * http://www.apache.org/licenses/LICENSE-2.0
21149 *
21150 * Unless required by applicable law or agreed to in writing, softw
21150are
21151 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21152 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
21153 * License for the specific language governing permissions and limitations
21154 * under the License.
21155 * ========================================================================== */
21156
21157/* ========================================================================== */
21158/* JSHint directives                                                          */
21159/*                                                                            */
21160/* global BootstrapTabHistory: true                                           */
21161/*                                                                            */
21162/* global document                                                            */
21163/* global jQuery                                                              */
21164/* global history                                                             */
21165/* global window                                                              */
21166/* ========================================================================== */
21167
21168/**
21169 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
21170 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
21171 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
21172 *
21173 * See the README for additional information.
21174 *
21175 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
21176 */
21177
21178BootstrapTabHistory = {
21179  options: {
21180    /**
21181     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
21182     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
21183     *
21184     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
21185     *
21186     * @public
21187     * @type {?number}
21188     */
21189    defaultAnchorYOffset: 0,
21190    /**
21191     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
21192     *
21193     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
21194     *
21195     * @public
21196     * @type {string}
21197     */
21198    defaultChanger: 'replace',
21199    /**
21200     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
21201     * `null` is passed as the third parameter to these calls.
21202     *
21203     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
21204     *
21205     * @public
21206     * @type {boolean}
21207     */
21208    defaultUpdateURL: false,
21209    /**
21210     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
21211     * load.
21212     *
21213     * @public
21214     * @type {boolean}
21215     */
21216    showTabsBasedOnAnchor: true
21217  }
21218};
21219
21220(function () {
21221  'use strict';
21222
21223  jQuery(function () {
21224    if(history && history.pushState && history.replaceState) {
21225      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
21226
21227      if(bootstrapTabHistory) {
21228        showTabsBasedOnState(bootstrapTabHistory);
21229      } else {
21230        showTabsBasedOnAnchor();
21231      }
21232
21233      backfillHistoryState();
21234
21235      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
21236      jQuery(window).on('popstate', onPopState);
21237    } else {
21238      showTabsBasedOnAnchor();
21239    }
21240  });
21241
21242  /**
21243   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
21244   *
21245   * @type {boolean}
21246   */
21247  var showingTabsBasedOnState = false;
21248
21249  /**
21250   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
21251   * `history.back` handling when `data-tab-history-update-url` is true.
21252   */
21253  function backfillHistoryState() {
21254    var newState = null;
21255
21256    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
21257      var $activeTabElement = jQuery(this);
21258      var selector = getTabSelector($activeTabElement);
21259
21260      if(selector) {
21261        var tabGroup = getTabGroup($activeTabElement);
21262
21263        if(tabGroup) {
21264          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
21265        }
21266      }
21267    });
21268
21269    if(newState) {
21270      history.replaceState(newState, '', null);
21271    }
21272  }
21273
21274  /**
21275   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
21276   * said bootstrapTabHistory attribute.
21277   *
21278   * @param {?object} existingState
21279   * @param {!string} tabGroup
21280   * @param {!string} selector
21281   * @returns {!object}
21282   */
21283  function createNewHistoryState(existingState, tabGroup, selector) {
21284    // Clone history.state and ensure it has a bootstrapTabHistory entry.
21285    var newState = jQuery.extend(true, {}, existingState, {
21286      bootstrapTabHistory: {}
21287    });
21288
21289    newState.bootstrapTabHistory[tabGroup] = selector;
21290
21291    return newState;
21292  }
21293
21294  /**
21295   * @param {jQuery} $tab
21296   * @returns {?string}
21297   */
21298  function getTabGroup($tab) {
21299    return parseTruthyAttributeValue($tab.data('tab-history'));
21300  }
21301
21302  /**
21303   * @param {jQuery} $tab
21304   * @returns {?string}
21305   */
21306  function getTabSelector($tab) {
21307    return $tab.data('target') || $tab.attr('href');
21308  }
21309
21310  /**
21311   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
21312   *
21313   * @param {jQuery.Event} shownEvt
21314   */
21315  function onShownTab(shownEvt) {
21316    if(!showingTabsBasedOnState) {
21317      var $activatedTab = jQuery(shownEvt.target);
21318      if ( $activatedTab.hasClass('panel-collapse') )
21319        $activatedTab = $activatedTab.closest('.panel').find('a');
21320      var selector = getTabSelector($activatedTab);
21321
21322      if(selector) {
21323        var tabGroup = getTabGroup($activatedTab);
21324
21325        if(tabGroup) {
21326          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
21327          var newState = createNewHistoryState(history.state, tabGroup, selector);
21328          var updateURL = (function ($activatedTab) {
21329            if(selector[0] === '#') {
21330              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
21331
21332              if(elementUpdateURLOption === undefined) {
21333                return BootstrapTabHistory.options.defaultUpdateURL;
21334              } else {
21335                return elementUpdateURLOption;
21336              }
21337            } else {
21338              return false;
21339            }
21340          })($activatedTab);
21341
21342          switch(historyChanger) {
21343            case 'push':
21344              history.pushState(newState, '', updateURL ? selector : null);
21345              break;
21346            case 'replace':
21347              history.replaceState(newState, '', updateURL ? selector : null);
21348              break;
21349            default:
21350              throw new Error('Unknown tab-history-changer: ' + historyChanger);
21351          }
21352        }
21353      }
21354    }
21355  }
21356
21357  /**
21358   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
21359   */
21360  function onPopState() {
21361    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
21362
21363    if(bootstrapTabHistory) {
21364      showTabsBasedOnState(bootstrapTabHistory);
21365    }
21366  }
21367
21368  /**
21369   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
21370   *
21371   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
21372   *
21373   * @param {*} value
21374   * @returns {*}
21375   */
21376  function parseTruthyAttributeValue(value) {
21377    if(value) {
21378      return value;
21379    } else if(value === '') {
21380      return true;
21381    } else {
21382      return value;
21383    }
21384  }
21385
21386  /**
21387   * Show tabs based upon the anchor component of `window.location`.
21388   */
21389  function showTabsBasedOnAnchor() {
21390    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
21391      var anchor = window.location && window.location.hash;
21392
21393      if(anchor) {
21394        var $tabElement = showTabForSelector(anchor);
21395
21396        if($tabElement && window.addEventListener && window.removeEventListener) {
21397          var anchorYOffset = (function ($tabElement) {
21398            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
21399
21400            if(elementSetting === undefined) {
21401              return BootstrapTabHistory.options.defaultAnchorYOffset;
21402            } else {
21403              return elementSetting;
21404            }
21405          })($tabElement);
21406
21407          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
21408          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
21409          //   `history.state` object should have been used (unless the browser did not support the modern History API).
21410          if(anchorYOffset || anchorYOffset === 0) {
21411            var scrollListener = function resetAnchorScroll () {
21412              window.removeEventListener('scroll', scrollListener);
21413              window.scrollTo(0, anchorYOffset);
21414            };
21415
21416            window.addEventListener('scroll', scrollListener);
21417          }
21418        }
21419      }
21420    }
21421  }
21422
21423  /**
21424   * Show a tab which corresponds to the provided selector.
21425   *
21426   * @param {string} selector - A CSS selector.
21427   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
21428   */
21429  function showTabForSelector(selector) {
21430    var $tabElement = (function (selector) {
21431      var $ret = null;
21432
21433      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
21434        var $potentialTab = jQuery(this);
21435
21436        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
21437          $ret = $potentialTab;
21438          return false;
vendor: 43,417 bytes, lines 21439-22653
21439        } else {
21440         return null;
21441        }
21442      });
21443
21444      return $ret;
21445    })(selector);
21446
21447    if($tabElement) {
21448      $tabElement.trigger('click');
21449      //$tabElement.tab('show');
21450    }
21451
21452    return $tabElement;
21453  }
21454
21455  /**
21456   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
21457   *
21458   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
21459   */
21460  function showTabsBasedOnState(bootstrapTabHistory) {
21461    showingTabsBasedOnState = true;
21462
21463    try {
21464      for(var k in bootstrapTabHistory) {
21465        if(bootstrapTabHistory.hasOwnProperty(k)) {
21466          showTabForSelector(bootstrapTabHistory[k]);
21467        }
21468      }
21469    } finally {
21470      showingTabsBasedOnState = false;
21471    }
21472  }
21473})();
21474
21475/*!
21476 * justifiedGallery - v3.8.1
21477 * http://miromannino.github.io/Justified-Gallery/
21478 * Copyright (c) 2020 Miro Mannino
21479 * Licensed under the MIT license.
21480 */
21481(function (factory) {
21482  if (typeof define === 'function' && define.amd) {
21483    // AMD. Register as an anonymous module.
21484    define(['jquery'], factory);
21485  } else if (typeof module === 'object' && module.exports) {
21486    // Node/CommonJS
21487    module.exports = function (root, jQuery) {
21488      if (jQuery === undefined) {
21489        // require('jQuery') returns a factory that requires window to
21490        // build a jQuery instance, we normalize how we use modules
21491        // that require this pattern but the window provided is a noop
21492        // if it's defined (how jquery works)
21493        if (typeof window !== 'undefined') {
21494          jQuery = require('jquery');
21495        }
21496        else {
21497          jQuery = require('jquery')(root);
21498        }
21499      }
21500      factory(jQuery);
21501      return jQuery;
21502    };
21503  } else {
21504    // Browser globals
21505    factory(jQuery);
21506  }
21507}(function ($) {
21508
21509  /**
21510   * Justified Gallery controller constructor
21511   *
21512   * @param $gallery the gallery to build
21513   * @param settings the settings (the defaults are in JustifiedGallery.defaults)
21514   * @constructor
21515   */
21516  var JustifiedGallery = function ($gallery, settings) {
21517
21518    this.settings = settings;
21519    this.checkSettings();
21520
21521    this.imgAnalyzerTimeout = null;
21522    this.entries = null;
21523    this.buildingRow = {
21524      entriesBuff: [],
21525      width: 0,
21526      height: 0,
21527      aspectRatio: 0
21528    };
21529    this.lastFetchedEntry = null;
21530    this.lastAnalyzedIndex = -1;
21531    this.yield = {
21532      every: 2, // do a flush every n flushes (must be greater than 1)
21533      flushed: 0 // flushed rows without a yield
21534    };
21535    this.border = settings.border >= 0 ? settings.border : settings.margins;
21536    this.maxRowHeight = this.retrieveMaxRowHeight();
21537    this.suffixRanges = this.retrieveSuffixRanges();
21538    this.offY = this.border;
21539    this.rows = 0;
21540    this.spinner = {
21541      phase: 0,
21542      timeSlot: 150,
21543      $el: $('<div class="jg-spinner"><span></span><span></span><span></span></div>'),
21544      intervalId: null
21545    };
21546    this.scrollBarOn = false;
21547    this.checkWidthIntervalId = null;
21548    this.galleryWidth = $gallery.width();
21549    this.$gallery = $gallery;
21550
21551  };
21552
21553  /** @returns {String} the best suffix given the width and the height */
21554  JustifiedGallery.prototype.getSuffix = function (width, height) {
21555    var longestSide, i;
21556    longestSide = (width > height) ? width : height;
21557    for (i = 0; i < this.suffixRanges.length; i++) {
21558      if (longestSide <= this.suffixRanges[i]) {
21559        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
21560      }
21561    }
21562    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
21563  };
21564
21565  /**
21566   * Remove the suffix from the string
21567   *
21568   * @returns {string} a new string without the suffix
21569   */
21570  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
21571    return str.substring(0, str.length - suffix.length);
21572  };
21573
21574  /**
21575   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
21576   */
21577  JustifiedGallery.prototype.endsWith = function (str, suffix) {
21578    return str.indexOf(suffix, str.length - suffix.length) !== -1;
21579  };
21580
21581  /**
21582   * Get the used suffix of a particular url
21583   *
21584   * @param str
21585   * @returns {String} return the used suffix
21586   */
21587  JustifiedGallery.prototype.getUsedSuffix = function (str) {
21588    for (var si in this.settings.sizeRangeSuffixes) {
21589      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
21590        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
21591        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
21592      }
21593    }
21594    return '';
21595  };
21596
21597  /**
21598   * Given an image src, with the width and the height, returns the new image src with the
21599   * best suffix to show the best quality thumbnail.
21600   *
21601   * @returns {String} the suffix to use
21602   */
21603  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
21604    var newImageSrc;
21605
21606    if (this.settings.thumbnailPath) {
21607      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
21608    } else {
21609      var matchRes = imageSrc.match(this.settings.extension);
21610      var ext = (matchRes !== null) ? matchRes[0] : '';
21611      newImageSrc = imageSrc.replace(this.settings.extension, '');
21612      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
21613      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
21614    }
21615
21616    return newImageSrc;
21617  };
21618
21619  /**
21620   * Shows the images that is in the given entry
21621   *
21622   * @param $entry the entry
21623   * @param callback the callback that is called when the show animation is finished
21624   */
21625  JustifiedGallery.prototype.showImg = function ($entry, callback) {
21626    if (this.settings.cssAnimation) {
21627      $entry.addClass('jg-entry-visible');
21628      if (callback) callback();
21629    } else {
21630      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
21631      $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
21632    }
21633  };
21634
21635  /**
21636   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
21637   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
21638   *
21639   * @param $image the image to analyze
21640   * @returns {String} the extracted src
21641   */
21642  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
21643    var imageSrc = $image.data('safe-src');
21644    var imageSrcLoc = 'data-safe-src';
21645    // Begin Uncode edit
21646    if (typeof imageSrc === 'undefined') {
21647    	var imageCurrentSrc = $image[0].currentSrc;
21648    	if (imageCurrentSrc) {
21649    		imageSrc = imageCurrentSrc;
21650    	} else {
21651    		imageSrc = $image.attr('src');
21652    	}
21653		imageSrcLoc = 'src';
21654    }
21655    // End Uncode edit
21656    $image.data('jg.originalSrc', imageSrc); // this is saved for the destroy method
21657    $image.data('jg.src', imageSrc); // this will change overtime
21658    $image.data('jg.originalSrcLoc', imageSrcLoc); // this is saved for the destroy method
21659    return imageSrc;
21660  };
21661
21662  /** @returns {jQuery} the image in the given entry */
21663  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
21664    var $img = $entry.find(this.settings.imgSelector);
21665    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
21666    return $img.length === 0 ? null : $img;
21667  };
21668
21669  /** @returns {jQuery} the caption in the given entry */
21670  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
21671    var $caption = $entry.find('> .jg-caption');
21672    return $caption.length === 0 ? null : $caption;
21673  };
21674
21675  /**
21676   * Display the entry
21677   *
21678   * @param {jQuery} $entry the entry to display
21679   * @param {int} x the x position where the entry must be positioned
21680   * @param y the y position where the entry must be positioned
21681   * @param imgWidth the image width
21682   * @param imgHeight the image height
21683   * @param rowHeight the row height of the row that owns the entry
21684   */
21685  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
21686    $entry.width(imgWidth);
21687    $entry.height(Math.floor(rowHeight));//hacked by Uncode
21688    $entry.css('top', Math.floor(y));//hacked by Uncode
21689    $entry.css('left', x);
21690
21691    var $image = this.imgFromEntry($entry);
21692    if ($image !== null) {
21693      $image.css('width', imgWidth);
21694      $image.css('height', imgHeight);
21695      $image.css('margin-left', - imgWidth / 2);
21696      $image.css('margin-top', - imgHeight / 2);
21697
21698      // Image reloading for an high quality of thumbnails
21699      var imageSrc = $image.data('jg.src');
21700      if (imageSrc) {
21701        imageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
21702
21703        $image.one('error', function () {
21704           this.resetImgSrc($image); //revert to the original thumbnail
21705        });
21706
21707        var loadNewImage = function () {
21708          // if (imageSrc !== newImageSrc) {
21709            $image.attr('src', imageSrc);
21710          // }
21711        };
21712
21713        if ($entry.data('jg.loaded') === 'skipped' && imageSrc) {
21714          this.onImageEvent(imageSrc, (function() {
21715            this.showImg($entry, loadNewImage); //load the new image after the fadeIn
21716            $entry.data('jg.loaded', true);
21717          }).bind(this));
21718        } else {
21719          this.showImg($entry, loadNewImage); //load the new image after the fadeIn
21720        }
21721
21722      }
21723
21724    } else {
21725      this.showImg($entry);
21726    }
21727
21728    this.displayEntryCaption($entry);
21729  };
21730
21731  /**
21732   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
21733   * or the 'title' attributes.
21734   *
21735   * @param {jQuery} $entry the entry to process
21736   */
21737  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
21738    var $image = this.imgFromEntry($entry);
21739    if ($image !== null && this.settings.captions) {
21740      var $imgCaption = this.captionFromEntry($entry);
21741
21742      // Create it if it doesn't exists
21743      if ($imgCaption === null) {
21744        var caption = $image.attr('alt');
21745        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
21746        if (this.isValidCaption(caption)) { // Create only we found something
21747          $imgCaption = $('<div class="jg-caption">' + caption + '</div>');
21748          $entry.append($imgCaption);
21749          $entry.data('jg.createdCaption', true);
21750        }
21751      }
21752
21753      // Create events (we check again the $imgCaption because it can be still inexistent)
21754      if ($imgCaption !== null) {
21755        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
21756        this.addCaptionEventsHandlers($entry);
21757      }
21758    } else {
21759      this.removeCaptionEventsHandlers($entry);
21760    }
21761  };
21762
21763  /**
21764   * Validates the caption
21765   *
21766   * @param caption The caption that should be validated
21767   * @return {boolean} Validation result
21768   */
21769  JustifiedGallery.prototype.isValidCaption = function (caption) {
21770    return (typeof caption !== 'undefined' && caption.length > 0);
21771  };
21772
21773  /**
21774   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
21775   * It shows the caption using jQuery (or using CSS if it is configured so)
21776   *
21777   * @param {Event} eventObject the event object
21778   */
21779  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
21780    var $caption = this.captionFromEntry($(eventObject.currentTarget));
21781    if (this.settings.cssAnimation) {
21782      $caption.addClass('jg-caption-visible').removeClass('jg-caption-hidden');
21783    } else {
21784      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
21785        this.settings.captionSettings.visibleOpacity);
21786    }
21787  };
21788
21789  /**
21790   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
21791   * It hides the caption using jQuery (or using CSS if it is configured so)
21792   *
21793   * @param {Event} eventObject the event object
21794   */
21795  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
21796    var $caption = this.captionFromEntry($(eventObject.currentTarget));
21797    if (this.settings.cssAnimation) {
21798      $caption.removeClass('jg-caption-visible').removeClass('jg-caption-hidden');
21799    } else {
21800      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
21801        this.settings.captionSettings.nonVisibleOpacity);
21802    }
21803  };
21804
21805  /**
21806   * Add the handlers of the entry for the caption
21807   *
21808   * @param $entry the entry to modify
21809   */
21810  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
21811    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
21812    if (typeof captionMouseEvents === 'undefined') {
21813      captionMouseEvents = {
21814        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
21815        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
21816      };
21817      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
21818      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
21819      $entry.data('jg.captionMouseEvents', captionMouseEvents);
21820    }
21821  };
21822
21823  /**
21824   * Remove the handlers of the entry for the caption
21825   *
21826   * @param $entry the entry to modify
21827   */
21828  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
21829    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
21830    if (typeof captionMouseEvents !== 'undefined') {
21831      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
21832      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
21833      $entry.removeData('jg.captionMouseEvents');
21834    }
21835  };
21836
21837  /**
21838   * Clear the building row data to be used for a new row
21839   */
21840  JustifiedGallery.prototype.clearBuildingRow = function () {
21841    this.buildingRow.entriesBuff = [];
21842    this.buildingRow.aspectRatio = 0;
21843    this.buildingRow.width = 0;
21844  };
21845
21846  /**
21847   * Justify the building row, preparing it to
21848   *
21849   * @param isLastRow
21850   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
21851   * @returns a boolean to know if the row has been justified or not
21852   */
21853  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow, hiddenRow) {
21854    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
21855    var minHeight = 0;
21856    var availableWidth = this.galleryWidth - 2 * this.border - (
21857      (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
21858    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
21859    var defaultRowHeight = this.settings.rowHeight;
21860    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
21861
21862    //Skip the last row if we can't justify it and the lastRow == 'hide'
21863    if (hiddenRow || (isLastRow && this.settings.lastRow === 'hide' && !justifiable)) {
21864      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21865        $entry = this.buildingRow.entriesBuff[i];
21866        if (this.settings.cssAnimation)
21867          $entry.removeClass('jg-entry-visible');
21868        else {
21869          $entry.stop().fadeTo(0, 0.1);
21870          $entry.find('> img, > a > img').fadeTo(0, 0);
21871        }
21872      }
21873      return -1;
21874    }
21875
21876    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
21877    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
21878      justify = false;
21879
21880      if (this.rows > 0) {
21881        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
21882        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
21883      }
21884    }
21885
21886    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21887      $entry = this.buildingRow.entriesBuff[i];
21888      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
21889
21890      if (justify) {
21891        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
21892        newImgH = rowHeight;
21893      } else {
21894        newImgW = defaultRowHeight * imgAspectRatio;
21895        newImgH = defaultRowHeight;
21896      }
21897
21898      availableWidth -= Math.round(newImgW);
21899      $entry.data('jg.jwidth', Math.round(newImgW));
21900      $entry.data('jg.jheight', Math.ceil(newImgH));
21901      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
21902    }
21903
21904    this.buildingRow.height = minHeight;
21905    return justify;
21906  };
21907
21908  /**
21909   * Flush a row: justify it, modify the gallery height accordingly to the row height
21910   *
21911   * @param isLastRow
21912   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
21913   */
21914  JustifiedGallery.prototype.flushRow = function (isLastRow, hiddenRow) {
21915    var settings = this.settings;
21916    var $entry, buildingRowRes, offX = this.border, i;
21917
21918    buildingRowRes = this.prepareBuildingRow(isLastRow, hiddenRow);
21919    if (hiddenRow || (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1)) {
21920      this.clearBuildingRow();
21921      return;
21922    }
21923
21924    if (this.maxRowHeight) {
21925      if (this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight;
21926    }
21927
21928    //Align last (unjustified) row
21929    if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) {
21930      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
21931
21932      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21933        $entry = this.buildingRow.entriesBuff[i];
21934        availableWidth -= $entry.data('jg.jwidth');
21935      }
21936
21937      if (settings.lastRow === 'center')
21938        offX += Math.round(availableWidth / 2);
21939      else if (settings.lastRow === 'right')
21940        offX += availableWidth;
21941    }
21942
21943    var lastEntryIdx = this.buildingRow.entriesBuff.length - 1;
21944    for (i = 0; i <= lastEntryIdx; i++) {
21945      $entry = this.buildingRow.entriesBuff[this.settings.rtl ? lastEntryIdx - i : i];
21946      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
21947      offX += $entry.data('jg.jwidth') + settings.margins;
21948    }
21949
21950    //Gallery Height
21951    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
21952    this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight());
21953
21954    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
21955      //Ready for a new row
21956      this.offY += this.buildingRow.height + settings.margins;
21957      this.rows += 1;
21958      this.clearBuildingRow();
21959      this.settings.triggerEvent.call(this, 'jg.rowflush');
21960    }
21961  };
21962
21963
21964  // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221
21965  var galleryPrevStaticHeight = 0;
21966
21967  JustifiedGallery.prototype.rememberGalleryHeight = function () {
21968    galleryPrevStaticHeight = this.$gallery.height();
21969    this.$gallery.height(galleryPrevStaticHeight);
21970  };
21971
21972  // grow only
21973  JustifiedGallery.prototype.setGalleryTempHeight = function (height) {
21974    galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight);
21975    this.$gallery.height(galleryPrevStaticHeight);
21976  };
21977
21978  JustifiedGallery.prototype.setGalleryFinalHeight = function (height) {
21979    galleryPrevStaticHeight = height;
21980    this.$gallery.height(height);
21981  };
21982
21983  /**
21984   * Checks the width of the gallery container, to know if a new justification is needed
21985   */
21986  JustifiedGallery.prototype.checkWidth = function () {
21987    this.checkWidthIntervalId = setInterval($.proxy(function () {
21988
21989      // if the gallery is not currently visible, abort.
21990      if (!this.$gallery.is(":visible")) return;
21991
21992      var galleryWidth = parseFloat(this.$gallery.width());
21993      if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
21994        this.galleryWidth = galleryWidth;
21995        this.rewind();
21996
21997        this.rememberGalleryHeight();
21998
21999        // Restart to analyze
22000        this.startImgAnalyzer(true);
22001      }
22002    }, this), this.settings.refreshTime);
22003  };
22004
22005  /**
22006   * @returns {boolean} a boolean saying if the spinner is active or not
22007   */
22008  JustifiedGallery.prototype.isSpinnerActive = function () {
22009    return this.spinner.intervalId !== null;
22010  };
22011
22012  /**
22013   * @returns {int} the spinner height
22014   */
22015  JustifiedGallery.prototype.getSpinnerHeight = function () {
22016    return this.spinner.$el.innerHeight();
22017  };
22018
22019  /**
22020   * Stops the spinner animation and modify the gallery height to exclude the spinner
22021   */
22022  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
22023    clearInterval(this.spinner.intervalId);
22024    this.spinner.intervalId = null;
22025    this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight());
22026    this.spinner.$el.detach();
22027  };
22028
22029  /**
22030   * Starts the spinner animation
22031   */
22032  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
22033    var spinnerContext = this.spinner;
22034    var $spinnerPoints = spinnerContext.$el.find('span');
22035    clearInterval(spinnerContext.intervalId);
22036    this.$gallery.append(spinnerContext.$el);
22037    this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight());
22038    spinnerContext.intervalId = setInterval(function () {
22039      if (spinnerContext.phase < $spinnerPoints.length) {
22040        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
22041      } else {
22042        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
22043      }
22044      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
22045    }, spinnerContext.timeSlot);
22046  };
22047
22048  /**
22049   * Rewind the image analysis to start from the first entry.
22050   */
22051  JustifiedGallery.prototype.rewind = function () {
22052    this.lastFetchedEntry = null;
22053    this.lastAnalyzedIndex = -1;
22054    this.offY = this.border;
22055    this.rows = 0;
22056    this.clearBuildingRow();
22057  };
22058
22059  /**
22060   * @returns {String} `settings.selector` rejecting spinner element
22061   */
22062  JustifiedGallery.prototype.getSelectorWithoutSpinner = function () {
22063    return this.settings.selector + ', div:not(.jg-spinner)';
22064  };
22065
22066  /**
22067   * @returns {Array} all entries matched by `settings.selector`
22068   */
22069  JustifiedGallery.prototype.getAllEntries = function () {
22070    var selector = this.getSelectorWithoutSpinner();
22071    return this.$gallery.children(selector).toArray();
22072  };
22073
22074  /**
22075   * Update the entries searching it from the justified gallery HTML element
22076   *
22077   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
22078   * @returns {boolean} true if some entries has been founded
22079   */
22080  JustifiedGallery.prototype.updateEntries = function (norewind) {
22081    var newEntries;
22082
22083    if (norewind && this.lastFetchedEntry != null) {
22084      var selector = this.getSelectorWithoutSpinner();
22085      newEntries = $(this.lastFetchedEntry).nextAll(selector).toArray();
22086    } else {
22087      this.entries = [];
22088      newEntries = this.getAllEntries();
22089    }
22090
22091    if (newEntries.length > 0) {
22092
22093      // Sort or randomize
22094      if ($.isFunction(this.settings.sort)) {
22095        newEntries = this.sortArray(newEntries);
22096      } else if (this.settings.randomize) {
22097        newEntries = this.shuffleArray(newEntries);
22098      }
22099      this.lastFetchedEntry = newEntries[newEntries.length - 1];
22100
22101      // Filter
22102      if (this.settings.filter) {
22103        newEntries = this.filterArray(newEntries);
22104      } else {
22105        this.resetFilters(newEntries);
22106      }
22107
22108    }
22109
22110    this.entries = this.entries.concat(newEntries);
22111    return true;
22112  };
22113
22114  /**
22115   * Apply the entries order to the DOM, iterating the entries and appending the images
22116   *
22117   * @param entries the entries that has been modified and that must be re-ordered in the DOM
22118   */
22119  JustifiedGallery.prototype.insertToGallery = function (entries) {
22120    var that = this;
22121    $.each(entries, function () {
22122      $(this).appendTo(that.$gallery);
22123    });
22124  };
22125
22126  /**
22127   * Shuffle the array using the Fisher-Yates shuffle algorithm
22128   *
22129   * @param a the array to shuffle
22130   * @return the shuffled array
22131   */
22132  JustifiedGallery.prototype.shuffleArray = function (a) {
22133    var i, j, temp;
22134    for (i = a.length - 1; i > 0; i--) {
22135      j = Math.floor(Math.random() * (i + 1));
22136      temp = a[i];
22137      a[i] = a[j];
22138      a[j] = temp;
22139    }
22140    this.insertToGallery(a);
22141    return a;
22142  };
22143
22144  /**
22145   * Sort the array using settings.comparator as comparator
22146   *
22147   * @param a the array to sort (it is sorted)
22148   * @return the sorted array
22149   */
22150  JustifiedGallery.prototype.sortArray = function (a) {
22151    a.sort(this.settings.sort);
22152    this.insertToGallery(a);
22153    return a;
22154  };
22155
22156  /**
22157   * Reset the filters removing the 'jg-filtered' class from all the entries
22158   *
22159   * @param a the array to reset
22160   */
22161  JustifiedGallery.prototype.resetFilters = function (a) {
22162    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
22163  };
22164
22165  /**
22166   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
22167   *
22168   * @param a the array to filter
22169   * @return the filtered array
22170   */
22171  JustifiedGallery.prototype.filterArray = function (a) {
22172    var settings = this.settings;
22173    if ($.type(settings.filter) === 'string') {
22174      // Filter only keeping the entries passed in the string
22175      return a.filter(function (el) {
22176        var $el = $(el);
22177        if ($el.is(settings.filter)) {
22178          $el.removeClass('jg-filtered');
22179          return true;
22180        } else {
22181          $el.addClass('jg-filtered').removeClass('jg-visible');
22182          return false;
22183        }
22184      });
22185    } else if ($.isFunction(settings.filter)) {
22186      // Filter using the passed function
22187      var filteredArr = a.filter(settings.filter);
22188      for (var i = 0; i < a.length; i++) {
22189        if (filteredArr.indexOf(a[i]) === -1) {
22190          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
22191        } else {
22192          $(a[i]).removeClass('jg-filtered');
22193        }
22194      }
22195      return filteredArr;
22196    }
22197  };
22198
22199  /**
22200   * Revert the image src to the default value.
22201   */
22202  JustifiedGallery.prototype.resetImgSrc = function ($img) {
22203    if ($img.data('jg.originalSrcLoc') === 'src') {
22204      $img.attr('src', $img.data('jg.originalSrc'));
22205    } else {
22206      $img.attr('src', '');
22207    }
22208  };
22209
22210  /**
22211   * Destroy the Justified Gallery instance.
22212   *
22213   * It clears all the css properties added in the style attributes. We doesn't backup the original
22214   * values for those css attributes, because it costs (performance) and because in general one
22215   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
22216   * classes). Creating a backup is also difficult because JG could be called multiple times and
22217   * with different style attributes.
22218   */
22219  JustifiedGallery.prototype.destroy = function () {
22220    clearInterval(this.checkWidthIntervalId);
22221    this.stopImgAnalyzerStarter();
22222
22223    // Get fresh entries list since filtered entries are absent in `this.entries`
22224    $.each(this.getAllEntries(), $.proxy(function (_, entry) {
22225      var $entry = $(entry);
22226
22227      // Reset entry style
22228      $entry.css('width', '');
22229      $entry.css('height', '');
22230      $entry.css('top', '');
22231      $entry.css('left', '');
22232      $entry.data('jg.loaded', undefined);
22233      $entry.removeClass('jg-entry jg-filtered jg-entry-visible');
22234
22235      // Reset image style
22236      var $img = this.imgFromEntry($entry);
22237      if ($img) {
22238        $img.css('width', '');
22239        $img.css('height', '');
22240        $img.css('margin-left', '');
22241        $img.css('margin-top', '');
22242        this.resetImgSrc($img);
22243        $img.data('jg.originalSrc', undefined);
22244        $img.data('jg.originalSrcLoc', undefined);
22245        $img.data('jg.src', undefined);
22246      }
22247
22248      // Remove caption
22249      this.removeCaptionEventsHandlers($entry);
22250      var $caption = this.captionFromEntry($entry);
22251      if ($entry.data('jg.createdCaption')) {
22252        // remove also the caption element (if created by jg)
22253        $entry.data('jg.createdCaption', undefined);
22254        if ($caption !== null) $caption.remove();
22255      } else {
22256        if ($caption !== null) $caption.fadeTo(0, 1);
22257      }
22258
22259    }, this));
22260
22261    this.$gallery.css('height', '');
22262    this.$gallery.removeClass('justified-gallery');
22263    this.$gallery.data('jg.controller', undefined);
22264    this.settings.triggerEvent.call(this, 'jg.destroy');
22265  };
22266
22267  /**
22268   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
22269   *
22270   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
22271   */
22272  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
22273    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
22274      var $entry = $(this.entries[i]);
22275      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
22276        var availableWidth = this.galleryWidth - 2 * this.border - (
22277          (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
22278        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
22279
22280        this.buildingRow.entriesBuff.push($entry);
22281        this.buildingRow.aspectRatio += imgAspectRatio;
22282        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
22283        this.lastAnalyzedIndex = i;
22284
22285        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
22286          this.flushRow(false, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
22287
22288          if (++this.yield.flushed >= this.yield.every) {
22289            this.startImgAnalyzer(isForResize);
22290            return;
22291          }
22292        }
22293      } else if ($entry.data('jg.loaded') !== 'error') {
22294        return;
22295      }
22296    }
22297
22298    // Last row flush (the row is not full)
22299    if (this.buildingRow.entriesBuff.length > 0) {
22300      this.flushRow(true, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
22301    }
22302
22303    if (this.isSpinnerActive()) {
22304      this.stopLoadingSpinnerAnimation();
22305    }
22306
22307    /* Stop, if there is, the timeout to start the analyzeImages.
22308     This is because an image can be set loaded, and the timeout can be set,
22309     but this image can be analyzed yet.
22310     */
22311    this.stopImgAnalyzerStarter();
22312
22313    this.setGalleryFinalHeight(this.galleryHeightToSet);
22314
22315    //On complete callback
22316    this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete');
22317  };
22318
22319  /**
22320   * Stops any ImgAnalyzer starter (that has an assigned timeout)
22321   */
22322  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
22323    this.yield.flushed = 0;
22324    if (this.imgAnalyzerTimeout !== null) {
22325      clearTimeout(this.imgAnalyzerTimeout);
22326      this.imgAnalyzerTimeout = null;
22327    }
22328  };
22329
22330  /**
22331   * Starts the image analyzer. It is not immediately called to let the browser to update the view
22332   *
22333   * @param isForResize specifies if the image analyzer must be called for resizing or not
22334   */
22335  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
22336    var that = this;
22337    this.stopImgAnalyzerStarter();
22338    this.imgAnalyzerTimeout = setTimeout(function () {
22339      that.analyzeImages(isForResize);
22340    }, 0.001); // we can't start it immediately due to a IE different behaviour
22341  };
22342
22343  /**
22344   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
22345   * because some browsers, with a 404 set complete = true.
22346   *
22347   * @param imageSrc the image src to load
22348   * @param onLoad callback that is called when the image has been loaded
22349   * @param onError callback that is called in case of an error
22350   */
22351  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
22352    if (!onLoad && !onError) return;
22353
22354    var memImage = new Image();
22355    var $memImage = $(memImage);
22356    if (onLoad) {
22357      $memImage.one('load', function () {
22358        $memImage.off('load error');
22359        onLoad(memImage);
22360      });
22361    }
22362    if (onError) {
22363      $memImage.one('error', function () {
22364        $memImage.off('load error');
22365        onError(memImage);
22366      });
22367    }
22368    memImage.src = imageSrc;
22369  };
22370
22371  /**
22372   * Init of Justified Gallery controlled
22373   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
22374   */
22375  JustifiedGallery.prototype.init = function () {
22376    var imagesToLoad = false, skippedImages = false, that = this;
22377    $.each(this.entries, function (index, entry) {
22378      var $entry = $(entry);
22379      var $image = that.imgFromEntry($entry);
22380
22381      $entry.addClass('jg-entry');
22382
22383      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
22384
22385        // Link Rel global overwrite
22386        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
22387
22388        // Link Target global overwrite
22389        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
22390
22391        if ($image !== null) {
22392
22393          // Image src
22394          var imageSrc = that.extractImgSrcFromImage($image);
22395
22396          /* If we have the height and the width, we don't wait that the image is loaded,
22397             but we start directly with the justification */
22398          if (that.settings.waitThumbnailsLoad === false || !imageSrc) {
22399            var width = parseFloat($image.attr('width'));
22400            var height = parseFloat($image.attr('height'));
22401            if ($image.prop('tagName') === 'svg') {
22402              width = parseFloat($image[0].getBBox().width);
22403              height = parseFloat($image[0].getBBox().height);
22404            }
22405            if (!isNaN(width) && !isNaN(height)) {
22406              $entry.data('jg.width', width);
22407              $entry.data('jg.height', height);
22408              $entry.data('jg.loaded', 'skipped');
22409              skippedImages = true;
22410              that.startImgAnalyzer(false);
22411              return true; // continue
22412            }
22413          }
22414
22415          $entry.data('jg.loaded', false);
22416          imagesToLoad = true;
22417
22418          // Spinner start
22419          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
22420
22421          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
22422            $entry.data('jg.width', loadImg.width);
22423            $entry.data('jg.height', loadImg.height);
22424            $entry.data('jg.loaded', true);
22425            that.startImgAnalyzer(false);
22426          }, function () { // image load error
22427            $entry.data('jg.loaded', 'error');
22428            that.startImgAnalyzer(false);
22429          });
22430
22431        } else {
22432          $entry.data('jg.loaded', true);
22433          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
22434          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
22435        }
22436
22437      }
22438
22439    });
22440
22441    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
22442    this.checkWidth();
22443  };
22444
22445  /**
22446   * Checks that it is a valid number. If a string is passed it is converted to a number
22447   *
22448   * @param settingContainer the object that contains the setting (to allow the conversion)
22449   * @param settingName the setting name
22450   */
22451  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
22452    if ($.type(settingContainer[settingName]) === 'string') {
22453      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
22454    }
22455
22456    if ($.type(settingContainer[settingName]) === 'number') {
22457      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
22458    } else {
22459      throw settingName + ' must be a number';
22460    }
22461  };
22462
22463  /**
22464   * Checks the sizeRangeSuffixes and, if necessary, converts
22465   * its keys from string (e.g. old settings with 'lt100') to int.
22466   */
22467  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
22468    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
22469      throw 'sizeRangeSuffixes must be defined and must be an object';
22470    }
22471
22472    var suffixRanges = [];
22473    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
22474      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
22475    }
22476
22477    var newSizeRngSuffixes = { 0: '' };
22478    for (var i = 0; i < suffixRanges.length; i++) {
22479      if ($.type(suffixRanges[i]) === 'string') {
22480        try {
22481          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
22482          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
22483        } catch (e) {
22484          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
22485        }
22486      } else {
22487        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
22488      }
22489    }
22490
22491    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
22492  };
22493
22494  /**
22495   * check and convert the maxRowHeight setting
22496   * requires rowHeight to be already set
22497   * TODO: should be always called when only rowHeight is changed
22498   * @return number or null
22499   */
22500  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
22501    var newMaxRowHeight = null;
22502    var rowHeight = this.settings.rowHeight;
22503
22504    if ($.type(this.settings.maxRowHeight) === 'string') {
22505      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
22506        newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
22507      } else {
22508        newMaxRowHeight = parseFloat(this.settings.maxRowHeight);
22509      }
22510    } else if ($.type(this.settings.maxRowHeight) === 'number') {
22511      newMaxRowHeight = this.settings.maxRowHeight;
22512    } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) {
22513      return null;
22514    } else {
22515      throw 'maxRowHeight must be a number or a percentage';
22516    }
22517
22518    // check if the converted value is not a number
22519    if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight';
22520
22521    // check values, maxRowHeight must be >= rowHeight
22522    if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight;
22523
22524    return newMaxRowHeight;
22525  };
22526
22527  /**
22528   * Checks the settings
22529   */
22530  JustifiedGallery.prototype.checkSettings = function () {
22531    this.checkSizeRangesSuffixes();
22532
22533    this.checkOrConvertNumber(this.settings, 'rowHeight');
22534    this.checkOrConvertNumber(this.settings, 'margins');
22535    this.checkOrConvertNumber(this.settings, 'border');
22536    this.checkOrConvertNumber(this.settings, 'maxRowsCount');
22537
22538    var lastRowModes = [
22539      'justify',
22540      'nojustify',
22541      'left',
22542      'center',
22543      'right',
22544      'hide'
22545    ];
22546    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
22547      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
22548    }
22549
22550    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
22551    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
22552      throw 'justifyThreshold must be in the interval [0,1]';
22553    }
22554    if ($.type(this.settings.cssAnimation) !== 'boolean') {
22555      throw 'cssAnimation must be a boolean';
22556    }
22557
22558    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
22559    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
22560
22561    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
22562    if (this.settings.captionSettings.visibleOpacity < 0 ||
22563      this.settings.captionSettings.visibleOpacity > 1) {
22564      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
22565    }
22566
22567    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
22568    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
22569      this.settings.captionSettings.nonVisibleOpacity > 1) {
22570      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
22571    }
22572
22573    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
22574    this.checkOrConvertNumber(this.settings, 'refreshTime');
22575    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
22576    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
22577    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
22578
22579    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
22580      throw 'sort must be false or a comparison function';
22581    }
22582
22583    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
22584      $.type(this.settings.filter) !== 'string') {
22585      throw 'filter must be false, a string or a filter function';
22586    }
22587  };
22588
22589  /**
22590   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
22591   * @returns {Array} sorted suffix ranges
22592   */
22593  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
22594    var suffixRanges = [];
22595    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
22596      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
22597    }
22598    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
22599    return suffixRanges;
22600  };
22601
22602  /**
22603   * Update the existing settings only changing some of them
22604   *
22605   * @param newSettings the new settings (or a subgroup of them)
22606   */
22607  JustifiedGallery.prototype.updateSettings = function (newSettings) {
22608    // In this case Justified Gallery has been called again changing only some options
22609    this.settings = $.extend({}, this.settings, newSettings);
22610    this.checkSettings();
22611
22612    // As reported in the settings: negative value = same as margins, 0 = disabled
22613    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
22614
22615    this.maxRowHeight = this.retrieveMaxRowHeight();
22616    this.suffixRanges = this.retrieveSuffixRanges();
22617  };
22618
22619  JustifiedGallery.prototype.defaults = {
22620    sizeRangeSuffixes: {}, /* e.g. Flickr configuration
22621        {
22622          100: '_t',  // used when longest is less than 100px
22623          240: '_m',  // used when longest is between 101px and 240px
22624          320: '_n',  // ...
22625          500: '',
22626          640: '_z',
22627          1024: '_b'  // used as else case because it is the last
22628        }
22629    */
22630    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
22631    path relative to a specific thumbnail size. The function should accept respectively three arguments:
22632    current path, width and height */
22633    rowHeight: 120, // required? required to be > 0?
22634    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
22635    // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
22636    // can't exceed 3 * rowHeight)
22637    maxRowsCount: 0, // maximum number of rows to be displayed (0 = disabled)
22638    margins: 1,
22639    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
22640
22641    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
22642
22643    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
22644                             * (i.e. lastRow setting is not considered) */
22645    waitThumbnailsLoad: true,
22646    captions: true,
22647    cssAnimation: true,
22648    imagesAnimationDuration: 500, // ignored with css animations
22649    captionSettings: { // ignored with css animations
22650      animationDuration: 500,
22651      visibleOpacity: 0.7,
22652      nonVisibleOpacity: 0.0
22653    },
22654    rel: null, // rewrite the rel of each analyzed links
22655    target: null, // rewrite the target of all links
22656    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
22657    refreshTime: 200, // time interval (in ms) to check if the page changes its width
22658    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
22659    randomize: false,
22660    rtl: false, // right-to-left mode
22661    sort: false, /*
22662      - false: to do not sort
22663      - function: to sort them using the function as comparator (see Array.prototype.sort())
22664    */
22665    filter: false, /*
22666      - false, null or undefined: for a disabled filter
22667      - a string: an entry is kept if entry.is(filter string) returns true
22668                  see jQuery's .is() function for further information
22669      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
22670                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
22671    */
22672    selector: 'a', // The selector that is used to know what are the entries of the gallery
22673    imgSelector: '> img, > a > img, > svg, > a > svg', // The selector that is used to know what are the images of each entry
22674    triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger
22675      this.$gallery.trigger(event);  // Consider that 'this' is this set to the JustifiedGallery object, so it can
22676    }                                // access to fields such as $gallery, useful to trigger events with jQuery.
22677  };
22678
22679
22680  /**
22681   * Justified Gallery plugin for jQuery
22682   *
22683   * Events
22684   *  - jg.complete : called when all the gallery has been created
22685   *  - jg.resize : called when the gallery has been resized
22686   *  - jg.rowflush : when a new row appears
22687   *
22688   * @param arg the action (or the settings) passed when the plugin is called
22689   * @returns {*} the object itself
22690   */
22691  $.fn.justifiedGallery = function (arg) {
22692    return this.each(function (index, gallery) {
22693
22694      var $gallery = $(gallery);
22695      $gallery.addClass('justified-gallery');
22696
22697      var controller = $gallery.data('jg.controller');
22698      if (typeof controller === 'undefined') {
22699        // Create controller and assign it to the object data
22700        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
22701          if (arg === 'destroy') return; // Just a call to an unexisting object
22702          throw 'The argument must be an object';
22703        }
22704        controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg));
22705        $gallery.data('jg.controller', controller);
22706      } else if (arg === 'norewind') {
22707        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
22708        // ... left to be more readable
22709      } else if (arg === 'destroy') {
22710        controller.destroy();
22711        return;
22712      } else {
22713        // In this case Justified Gallery has been called again changing only some options
22714        controller.updateSettings(arg);
22715        controller.rewind();
22716      }
22717
22718      // Update the entries list
22719      if (!controller.updateEntries(arg === 'norewind')) return;
22720
22721      // Init justified gallery
22722      controller.init();
22723
22724    });
22725  };
22726
22727}));
22728
22729/*!
22730* Customized version of iScroll.js 0.0.1
22731* It fixes bugs affecting its integration with fullpage.js
22732*/
22733/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
22734(function (window, document, Math) {
22735var rAF = window.requestAnimationFrame  ||
22736    window.webkitRequestAnimationFrame  ||
22737    window.mozRequestAnimationFrame     ||
22738    window.oRequestAnimationFrame       ||
22739    window.msRequestAnimationFrame      ||
22740    function (callback) { window.setTimeout(callback, 1000 / 60); };
22741
22742var utils = (function () {
22743    var me = {};
22744
22745    var _elementStyle = document.createElement('div').style;
22746    var _vendor = (function () {
22747        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
22748            transform,
22749            i = 0,
22750            l = vendors.length;
22751
22752        for ( ; i < l; i++ ) {
22753            transform = vendors[i] + 'ransform';
22754            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
22755        }
22756
22757        return false;
vendor: 5,154 bytes, lines 22758-22910
22758    })();
22759
22760    function _prefixStyle (style) {
22761        if ( _vendor === false ) return false;
22762        if ( _vendor === '' ) return style;
22763        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
22764    }
22765
22766    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
22767
22768    me.extend = function (target, obj) {
22769        for ( var i in obj ) {
22770            target[i] = obj[i];
22771        }
22772    };
22773
22774    me.addEvent = function (el, type, fn, capture) {
22775        el.addEventListener(type, fn, !!capture);
22776    };
22777
22778    me.removeEvent = function (el, type, fn, capture) {
22779        el.removeEventListener(type, fn, !!capture);
22780    };
22781
22782    me.prefixPointerEvent = function (pointerEvent) {
22783        return window.MSPointerEvent ?
22784            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
22785            pointerEvent;
22786    };
22787
22788    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
22789        var distance = current - start,
22790            speed = Math.abs(distance) / time,
22791            destination,
22792            duration;
22793
22794        deceleration = deceleration === undefined ? 0.0006 : deceleration;
22795
22796        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
22797        duration = speed / deceleration;
22798
22799        if ( destination < lowerMargin ) {
22800            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
22801            distance = Math.abs(destination - current);
22802            duration = distance / speed;
22803        } else if ( destination > 0 ) {
22804            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
22805            distance = Math.abs(current) + destination;
22806            duration = distance / speed;
22807        }
22808
22809        return {
22810            destination: Math.round(destination),
22811            duration: duration
22812        };
22813    };
22814
22815    var _transform = _prefixStyle('transform');
22816
22817    me.extend(me, {
22818        hasTransform: _transform !== false,
22819        hasPerspective: _prefixStyle('perspective') in _elementStyle,
22820        hasTouch: 'ontouchstart' in window,
22821        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
22822        hasTransition: _prefixStyle('transition') in _elementStyle
22823    });
22824
22825    /*
22826    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
22827    - galaxy S2 is ok
22828    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
22829    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22830   - galaxy S3 is badAndroid (stock brower, webview)
22831     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22832   - galaxy S4 is badAndroid (stock brower, webview)
22833     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22834   - galaxy S5 is OK
22835     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
22836   - galaxy S6 is OK
22837     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
22838  */
22839    me.isBadAndroid = (function() {
22840        var appVersion = window.navigator.appVersion;
22841        // Android browser is not a chrome browser.
22842        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
22843            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
22844            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
22845                return parseFloat(safariVersion[1]) < 535.19;
22846            } else {
22847                return true;
22848            }
22849        } else {
22850            return false;
22851        }
22852    })();
22853
22854    me.extend(me.style = {}, {
22855        transform: _transform,
22856        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
22857        transitionDuration: _prefixStyle('transitionDuration'),
22858        transitionDelay: _prefixStyle('transitionDelay'),
22859        transformOrigin: _prefixStyle('transformOrigin')
22860    });
22861
22862    me.hasClass = function (e, c) {
22863        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
22864        return re.test(e.className);
22865    };
22866
22867    me.addClass = function (e, c) {
22868        if ( me.hasClass(e, c) ) {
22869            return;
22870        }
22871
22872        var newclass = e.className.split(' ');
22873        newclass.push(c);
22874        e.className = newclass.join(' ');
22875    };
22876
22877    me.removeClass = function (e, c) {
22878        if ( !me.hasClass(e, c) ) {
22879            return;
22880        }
22881
22882        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
22883        e.className = e.className.replace(re, ' ');
22884    };
22885
22886    me.offset = function (el) {
22887        var left = -el.offsetLeft,
22888            top = -el.offsetTop;
22889
22890        // jshint -W084
22891        while (el = el.offsetParent) {
22892            left -= el.offsetLeft;
22893            top -= el.offsetTop;
22894        }
22895        // jshint +W084
22896
22897        return {
22898            left: left,
22899            top: top
22900        };
22901    };
22902
22903    me.preventDefaultException = function (el, exceptions) {
22904        for ( var i in exceptions ) {
22905            if ( exceptions[i].test(el[i]) ) {
22906                return true;
22907            }
22908        }
22909
22910        return false;
vendor: 5,660 bytes, lines 22911-23076
22911    };
22912
22913    me.extend(me.eventType = {}, {
22914        touchstart: 1,
22915        touchmove: 1,
22916        touchend: 1,
22917
22918        mousedown: 2,
22919        mousemove: 2,
22920        mouseup: 2,
22921
22922        pointerdown: 3,
22923        pointermove: 3,
22924        pointerup: 3,
22925
22926        MSPointerDown: 3,
22927        MSPointerMove: 3,
22928        MSPointerUp: 3
22929    });
22930
22931    me.extend(me.ease = {}, {
22932        quadratic: {
22933            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
22934            fn: function (k) {
22935                return k * ( 2 - k );
22936            }
22937        },
22938        circular: {
22939            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)
22940            fn: function (k) {
22941                return Math.sqrt( 1 - ( --k * k ) );
22942            }
22943        },
22944        back: {
22945            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
22946            fn: function (k) {
22947                var b = 4;
22948                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
22949            }
22950        },
22951        bounce: {
22952            style: '',
22953            fn: function (k) {
22954                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
22955                    return 7.5625 * k * k;
22956                } else if ( k < ( 2 / 2.75 ) ) {
22957                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
22958                } else if ( k < ( 2.5 / 2.75 ) ) {
22959                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
22960                } else {
22961                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
22962                }
22963            }
22964        },
22965        elastic: {
22966            style: '',
22967            fn: function (k) {
22968                var f = 0.22,
22969                    e = 0.4;
22970
22971                if ( k === 0 ) { return 0; }
22972                if ( k == 1 ) { return 1; }
22973
22974                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
22975            }
22976        }
22977    });
22978
22979    me.tap = function (e, eventName) {
22980        var ev = document.createEvent('Event');
22981        ev.initEvent(eventName, true, true);
22982        ev.pageX = e.pageX;
22983        ev.pageY = e.pageY;
22984        e.target.dispatchEvent(ev);
22985    };
22986
22987    me.click = function (e) {
22988        var target = e.target,
22989            ev;
22990
22991        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
22992            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
22993            // initMouseEvent is deprecated.
22994            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
22995            ev.initEvent('click', true, true);
22996            ev.view = e.view || window;
22997            ev.detail = 1;
22998            ev.screenX = target.screenX || 0;
22999            ev.screenY = target.screenY || 0;
23000            ev.clientX = target.clientX || 0;
23001            ev.clientY = target.clientY || 0;
23002            ev.ctrlKey = !!e.ctrlKey;
23003            ev.altKey = !!e.altKey;
23004            ev.shiftKey = !!e.shiftKey;
23005            ev.metaKey = !!e.metaKey;
23006            ev.button = 0;
23007            ev.relatedTarget = null;
23008            ev._constructed = true;
23009            target.dispatchEvent(ev);
23010        }
23011    };
23012
23013    return me;
23014})();
23015function IScroll (el, options) {
23016    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
23017    this.scroller = this.wrapper.children[0];
23018    this.scrollerStyle = this.scroller.style;       // cache style for better performance
23019
23020    this.options = {
23021
23022        resizeScrollbars: true,
23023
23024        mouseWheelSpeed: 20,
23025
23026        snapThreshold: 0.334,
23027
23028// INSERT POINT: OPTIONS
23029        disablePointer : !utils.hasPointer,
23030        disableTouch : utils.hasPointer || !utils.hasTouch,
23031        disableMouse : utils.hasPointer || utils.hasTouch,
23032        startX: 0,
23033        startY: 0,
23034        scrollY: true,
23035        directionLockThreshold: 5,
23036        momentum: true,
23037
23038        bounce: true,
23039        bounceTime: 600,
23040        bounceEasing: '',
23041
23042        preventDefault: true,
23043        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|LABEL)$/ },
23044
23045        HWCompositing: true,
23046        useTransition: true,
23047        useTransform: true,
23048        bindToWrapper: typeof window.onmousedown === "undefined"
23049    };
23050
23051    for ( var i in options ) {
23052        this.options[i] = options[i];
23053    }
23054
23055    // Normalize options
23056    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
23057
23058    this.options.useTransition = utils.hasTransition && this.options.useTransition;
23059    this.options.useTransform = utils.hasTransform && this.options.useTransform;
23060
23061    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
23062    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
23063
23064    // If you want eventPassthrough I have to lock one of the axes
23065    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
23066    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
23067
23068    // With eventPassthrough we also need lockDirection mechanism
23069    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
23070    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
23071
23072    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
23073
23074    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
23075
23076    if ( this.options.tap === true ) {
vendor: 4,893 bytes, lines 23077-23248
23077        this.options.tap = 'tap';
23078    }
23079
23080    // https://github.com/cubiq/iscroll/issues/1029
23081    if (!this.options.useTransition && !this.options.useTransform) {
23082        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
23083            this.scrollerStyle.position = "relative";
23084        }
23085    }
23086
23087    if ( this.options.shrinkScrollbars == 'scale' ) {
23088        this.options.useTransition = false;
23089    }
23090
23091    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
23092
23093// INSERT POINT: NORMALIZATION
23094
23095    // Some defaults
23096    this.x = 0;
23097    this.y = 0;
23098    this.directionX = 0;
23099    this.directionY = 0;
23100    this._events = {};
23101
23102// INSERT POINT: DEFAULTS
23103
23104    this._init();
23105    this.refresh();
23106
23107    this.scrollTo(this.options.startX, this.options.startY);
23108    this.enable();
23109}
23110
23111IScroll.prototype = {
23112    version: '5.2.0',
23113
23114    _init: function () {
23115        this._initEvents();
23116
23117        if ( this.options.scrollbars || this.options.indicators ) {
23118            this._initIndicators();
23119        }
23120
23121        if ( this.options.mouseWheel ) {
23122            this._initWheel();
23123        }
23124
23125        if ( this.options.snap ) {
23126            this._initSnap();
23127        }
23128
23129        if ( this.options.keyBindings ) {
23130            this._initKeys();
23131        }
23132
23133// INSERT POINT: _init
23134
23135    },
23136
23137    destroy: function () {
23138        this._initEvents(true);
23139        clearTimeout(this.resizeTimeout);
23140        this.resizeTimeout = null;
23141        this._execEvent('destroy');
23142    },
23143
23144    _transitionEnd: function (e) {
23145        if ( e.target != this.scroller || !this.isInTransition ) {
23146            return;
23147        }
23148
23149        this._transitionTime();
23150        if ( !this.resetPosition(this.options.bounceTime) ) {
23151            this.isInTransition = false;
23152            this._execEvent('scrollEnd');
23153        }
23154    },
23155
23156    _start: function (e) {
23157        // React to left mouse button only
23158        if ( utils.eventType[e.type] != 1 ) {
23159          // for button property
23160          // http://unixpapa.com/js/mouse.html
23161          var button;
23162        if (!e.which) {
23163          /* IE case */
23164          button = (e.button < 2) ? 0 :
23165                   ((e.button == 4) ? 1 : 2);
23166        } else {
23167          /* All others */
23168          button = e.button;
23169        }
23170            if ( button !== 0 ) {
23171                return;
23172            }
23173        }
23174
23175        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
23176            return;
23177        }
23178
23179        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
23180            e.preventDefault();
23181        }
23182
23183        var point = e.touches ? e.touches[0] : e,
23184            pos;
23185
23186        this.initiated  = utils.eventType[e.type];
23187        this.moved      = false;
23188        this.distX      = 0;
23189        this.distY      = 0;
23190        this.directionX = 0;
23191        this.directionY = 0;
23192        this.directionLocked = 0;
23193
23194        this.startTime = utils.getTime();
23195
23196        if ( this.options.useTransition && this.isInTransition ) {
23197            this._transitionTime();
23198            this.isInTransition = false;
23199            pos = this.getComputedPosition();
23200            this._translate(Math.round(pos.x), Math.round(pos.y));
23201            this._execEvent('scrollEnd');
23202        } else if ( !this.options.useTransition && this.isAnimating ) {
23203            this.isAnimating = false;
23204            this._execEvent('scrollEnd');
23205        }
23206
23207        this.startX    = this.x;
23208        this.startY    = this.y;
23209        this.absStartX = this.x;
23210        this.absStartY = this.y;
23211        this.pointX    = point.pageX;
23212        this.pointY    = point.pageY;
23213
23214        this._execEvent('beforeScrollStart');
23215    },
23216
23217    _move: function (e) {
23218        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
23219            return;
23220        }
23221
23222        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
23223            e.preventDefault();
23224        }
23225
23226        var point       = e.touches ? e.touches[0] : e,
23227            deltaX      = point.pageX - this.pointX,
23228            deltaY      = point.pageY - this.pointY,
23229            timestamp   = utils.getTime(),
23230            newX, newY,
23231            absDistX, absDistY;
23232
23233        this.pointX     = point.pageX;
23234        this.pointY     = point.pageY;
23235
23236        this.distX      += deltaX;
23237        this.distY      += deltaY;
23238        absDistX        = Math.abs(this.distX);
23239        absDistY        = Math.abs(this.distY);
23240
23241        // We need to move at least 10 pixels for the scrolling to initiate
23242        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
23243            return;
23244        }
23245
23246        // If you are scrolling in one direction lock the other
23247        if ( !this.directionLocked && !this.options.freeScroll ) {
23248            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
vendor: 6,057 bytes, lines 23249-23435
23249                this.directionLocked = 'h';     // lock horizontally
23250            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
23251                this.directionLocked = 'v';     // lock vertically
23252            } else {
23253                this.directionLocked = 'n';     // no lock
23254            }
23255        }
23256
23257        if ( this.directionLocked == 'h' ) {
23258            if ( this.options.eventPassthrough == 'vertical' ) {
23259                e.preventDefault();
23260            } else if ( this.options.eventPassthrough == 'horizontal' ) {
23261                this.initiated = false;
23262                return;
23263            }
23264
23265            deltaY = 0;
23266        } else if ( this.directionLocked == 'v' ) {
23267            if ( this.options.eventPassthrough == 'horizontal' ) {
23268                e.preventDefault();
23269            } else if ( this.options.eventPassthrough == 'vertical' ) {
23270                this.initiated = false;
23271                return;
23272            }
23273
23274            deltaX = 0;
23275        }
23276
23277        deltaX = this.hasHorizontalScroll ? deltaX : 0;
23278        deltaY = this.hasVerticalScroll ? deltaY : 0;
23279
23280        newX = this.x + deltaX;
23281        newY = this.y + deltaY;
23282
23283        // Slow down if outside of the boundaries
23284        if ( newX > 0 || newX < this.maxScrollX ) {
23285            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
23286        }
23287        if ( newY > 0 || newY < this.maxScrollY ) {
23288            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
23289        }
23290
23291        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
23292        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
23293
23294        if ( !this.moved ) {
23295            this._execEvent('scrollStart');
23296        }
23297
23298        this.moved = true;
23299
23300        this._translate(newX, newY);
23301
23302/* REPLACE START: _move */
23303
23304        if ( timestamp - this.startTime > 300 ) {
23305            this.startTime = timestamp;
23306            this.startX = this.x;
23307            this.startY = this.y;
23308        }
23309
23310/* REPLACE END: _move */
23311
23312    },
23313
23314    _end: function (e) {
23315        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
23316            return;
23317        }
23318
23319        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
23320            e.preventDefault();
23321        }
23322
23323        var point = e.changedTouches ? e.changedTouches[0] : e,
23324            momentumX,
23325            momentumY,
23326            duration = utils.getTime() - this.startTime,
23327            newX = Math.round(this.x),
23328            newY = Math.round(this.y),
23329            distanceX = Math.abs(newX - this.startX),
23330            distanceY = Math.abs(newY - this.startY),
23331            time = 0,
23332            easing = '';
23333
23334        this.isInTransition = 0;
23335        this.initiated = 0;
23336        this.endTime = utils.getTime();
23337
23338        // reset if we are outside of the boundaries
23339        if ( this.resetPosition(this.options.bounceTime) ) {
23340            return;
23341        }
23342
23343        this.scrollTo(newX, newY);  // ensures that the last position is rounded
23344
23345        // we scrolled less than 10 pixels
23346        if ( !this.moved ) {
23347            if ( this.options.tap ) {
23348                utils.tap(e, this.options.tap);
23349            }
23350
23351            if ( this.options.click ) {
23352                utils.click(e);
23353            }
23354
23355            this._execEvent('scrollCancel');
23356            return;
23357        }
23358
23359        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
23360            this._execEvent('flick');
23361            return;
23362        }
23363
23364        // start momentum animation if needed
23365        if ( this.options.momentum && duration < 300 ) {
23366            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 };
23367            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 };
23368            newX = momentumX.destination;
23369            newY = momentumY.destination;
23370            time = Math.max(momentumX.duration, momentumY.duration);
23371            this.isInTransition = 1;
23372        }
23373
23374
23375        if ( this.options.snap ) {
23376            var snap = this._nearestSnap(newX, newY);
23377            this.currentPage = snap;
23378            time = this.options.snapSpeed || Math.max(
23379                    Math.max(
23380                        Math.min(Math.abs(newX - snap.x), 1000),
23381                        Math.min(Math.abs(newY - snap.y), 1000)
23382                    ), 300);
23383            newX = snap.x;
23384            newY = snap.y;
23385
23386            this.directionX = 0;
23387            this.directionY = 0;
23388            easing = this.options.bounceEasing;
23389        }
23390
23391// INSERT POINT: _end
23392
23393        if ( newX != this.x || newY != this.y ) {
23394            // change easing function when scroller goes out of the boundaries
23395            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
23396                easing = utils.ease.quadratic;
23397            }
23398
23399            this.scrollTo(newX, newY, time, easing);
23400            return;
23401        }
23402
23403        this._execEvent('scrollEnd');
23404    },
23405
23406    _resize: function () {
23407        var that = this;
23408
23409        clearTimeout(this.resizeTimeout);
23410
23411        this.resizeTimeout = setTimeout(function () {
23412            that.refresh();
23413        }, this.options.resizePolling);
23414    },
23415
23416    resetPosition: function (time) {
23417        var x = this.x,
23418            y = this.y;
23419
23420        time = time || 0;
23421
23422        if ( !this.hasHorizontalScroll || this.x > 0 ) {
23423            x = 0;
23424        } else if ( this.x < this.maxScrollX ) {
23425            x = this.maxScrollX;
23426        }
23427
23428        if ( !this.hasVerticalScroll || this.y > 0 ) {
23429            y = 0;
23430        } else if ( this.y < this.maxScrollY ) {
23431            y = this.maxScrollY;
23432        }
23433
23434        if ( x == this.x && y == this.y ) {
23435            return false;
vendor: 5,509 bytes, lines 23436-23640
23436        }
23437
23438        this.scrollTo(x, y, time, this.options.bounceEasing);
23439
23440        return true;
23441    },
23442
23443    disable: function () {
23444        this.enabled = false;
23445    },
23446
23447    enable: function () {
23448        this.enabled = true;
23449    },
23450
23451    refresh: function () {
23452        var rf = this.wrapper.offsetHeight;     // Force reflow
23453
23454        this.wrapperWidth   = this.wrapper.clientWidth;
23455        this.wrapperHeight  = this.wrapper.clientHeight;
23456
23457/* REPLACE START: refresh */
23458
23459        this.scrollerWidth  = this.scroller.offsetWidth;
23460        this.scrollerHeight = this.scroller.offsetHeight;
23461
23462        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
23463        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
23464
23465/* REPLACE END: refresh */
23466
23467        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
23468        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
23469
23470        if ( !this.hasHorizontalScroll ) {
23471            this.maxScrollX = 0;
23472            this.scrollerWidth = this.wrapperWidth;
23473        }
23474
23475        if ( !this.hasVerticalScroll ) {
23476            this.maxScrollY = 0;
23477            this.scrollerHeight = this.wrapperHeight;
23478        }
23479
23480        this.endTime = 0;
23481        this.directionX = 0;
23482        this.directionY = 0;
23483
23484        this.wrapperOffset = utils.offset(this.wrapper);
23485
23486        this._execEvent('refresh');
23487
23488        this.resetPosition();
23489
23490// INSERT POINT: _refresh
23491
23492    },
23493
23494
23495    on: function (type, fn) {
23496        if ( !this._events[type] ) {
23497            this._events[type] = [];
23498        }
23499
23500        this._events[type].push(fn);
23501    },
23502
23503    off: function (type, fn) {
23504        if ( !this._events[type] ) {
23505            return;
23506        }
23507
23508        var index = this._events[type].indexOf(fn);
23509
23510        if ( index > -1 ) {
23511            this._events[type].splice(index, 1);
23512        }
23513    },
23514
23515    _execEvent: function (type) {
23516        if ( !this._events[type] ) {
23517            return;
23518        }
23519
23520        var i = 0,
23521            l = this._events[type].length;
23522
23523        if ( !l ) {
23524            return;
23525        }
23526
23527        for ( ; i < l; i++ ) {
23528            this._events[type][i].apply(this, [].slice.call(arguments, 1));
23529        }
23530    },
23531
23532    scrollBy: function (x, y, time, easing) {
23533        x = this.x + x;
23534        y = this.y + y;
23535        time = time || 0;
23536
23537        this.scrollTo(x, y, time, easing);
23538    },
23539
23540    scrollTo: function (x, y, time, easing) {
23541        easing = easing || utils.ease.circular;
23542
23543        this.isInTransition = this.options.useTransition && time > 0;
23544        var transitionType = this.options.useTransition && easing.style;
23545        if ( !time || transitionType ) {
23546                if(transitionType) {
23547                    this._transitionTimingFunction(easing.style);
23548                    this._transitionTime(time);
23549                }
23550            this._translate(x, y);
23551        } else {
23552            this._animate(x, y, time, easing.fn);
23553        }
23554    },
23555
23556    scrollToElement: function (el, time, offsetX, offsetY, easing) {
23557        el = el.nodeType ? el : this.scroller.querySelector(el);
23558
23559        if ( !el ) {
23560            return;
23561        }
23562
23563        var pos = utils.offset(el);
23564
23565        pos.left -= this.wrapperOffset.left;
23566        pos.top  -= this.wrapperOffset.top;
23567
23568        // if offsetX/Y are true we center the element to the screen
23569        if ( offsetX === true ) {
23570            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
23571        }
23572        if ( offsetY === true ) {
23573            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
23574        }
23575
23576        pos.left -= offsetX || 0;
23577        pos.top  -= offsetY || 0;
23578
23579        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
23580        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
23581
23582        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
23583
23584        this.scrollTo(pos.left, pos.top, time, easing);
23585    },
23586
23587    _transitionTime: function (time) {
23588        if (!this.options.useTransition) {
23589            return;
23590        }
23591        time = time || 0;
23592        var durationProp = utils.style.transitionDuration;
23593        if(!durationProp) {
23594            return;
23595        }
23596
23597        this.scrollerStyle[durationProp] = time + 'ms';
23598
23599        if ( !time && utils.isBadAndroid ) {
23600            this.scrollerStyle[durationProp] = '0.0001ms';
23601            // remove 0.0001ms
23602            var self = this;
23603            rAF(function() {
23604                if(self.scrollerStyle[durationProp] === '0.0001ms') {
23605                    self.scrollerStyle[durationProp] = '0s';
23606                }
23607            });
23608        }
23609
23610
23611        if ( this.indicators ) {
23612            for ( var i = this.indicators.length; i--; ) {
23613                this.indicators[i].transitionTime(time);
23614            }
23615        }
23616
23617
23618// INSERT POINT: _transitionTime
23619
23620    },
23621
23622    _transitionTimingFunction: function (easing) {
23623        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
23624
23625
23626        if ( this.indicators ) {
23627            for ( var i = this.indicators.length; i--; ) {
23628                this.indicators[i].transitionTimingFunction(easing);
23629            }
23630        }
23631
23632
23633// INSERT POINT: _transitionTimingFunction
23634
23635    },
23636
23637    _translate: function (x, y) {
23638        //Uncode addition
23639        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
23640            return false;
vendor: 9,939 bytes, lines 23641-23952
23641
23642        if ( this.options.useTransform ) {
23643
23644/* REPLACE START: _translate */
23645
23646            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
23647
23648/* REPLACE END: _translate */
23649
23650        } else {
23651            x = Math.round(x);
23652            y = Math.round(y);
23653            this.scrollerStyle.left = x + 'px';
23654            this.scrollerStyle.top = y + 'px';
23655        }
23656
23657        this.x = x;
23658        this.y = y;
23659
23660
23661        if ( this.indicators ) {
23662            for ( var i = this.indicators.length; i--; ) {
23663                this.indicators[i].updatePosition();
23664            }
23665        }
23666
23667        //Uncode addition
23668        var uncodevent = new CustomEvent('fp-slide-scroll');
23669        window.dispatchEvent(uncodevent);
23670
23671// INSERT POINT: _translate
23672
23673    },
23674
23675    _initEvents: function (remove) {
23676        var eventType = remove ? utils.removeEvent : utils.addEvent,
23677            target = this.options.bindToWrapper ? this.wrapper : window;
23678
23679        eventType(window, 'orientationchange', this);
23680        eventType(window, 'resize', this);
23681
23682        if ( this.options.click ) {
23683            eventType(this.wrapper, 'click', this, true);
23684        }
23685
23686        if ( !this.options.disableMouse ) {
23687            eventType(this.wrapper, 'mousedown', this);
23688            eventType(target, 'mousemove', this);
23689            eventType(target, 'mousecancel', this);
23690            eventType(target, 'mouseup', this);
23691        }
23692
23693        if ( utils.hasPointer && !this.options.disablePointer ) {
23694            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
23695            eventType(target, utils.prefixPointerEvent('pointermove'), this);
23696            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
23697            eventType(target, utils.prefixPointerEvent('pointerup'), this);
23698        }
23699
23700        if ( utils.hasTouch && !this.options.disableTouch ) {
23701            eventType(this.wrapper, 'touchstart', this);
23702            eventType(target, 'touchmove', this);
23703            eventType(target, 'touchcancel', this);
23704            eventType(target, 'touchend', this);
23705        }
23706
23707        eventType(this.scroller, 'transitionend', this);
23708        eventType(this.scroller, 'webkitTransitionEnd', this);
23709        eventType(this.scroller, 'oTransitionEnd', this);
23710        eventType(this.scroller, 'MSTransitionEnd', this);
23711    },
23712
23713    getComputedPosition: function () {
23714        var matrix = window.getComputedStyle(this.scroller, null),
23715            x, y;
23716
23717        if ( this.options.useTransform ) {
23718            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
23719            x = +(matrix[12] || matrix[4]);
23720            y = +(matrix[13] || matrix[5]);
23721        } else {
23722            x = +matrix.left.replace(/[^-\d.]/g, '');
23723            y = +matrix.top.replace(/[^-\d.]/g, '');
23724        }
23725
23726        return { x: x, y: y };
23727    },
23728    _initIndicators: function () {
23729        var interactive = this.options.interactiveScrollbars,
23730            customStyle = typeof this.options.scrollbars != 'string',
23731            indicators = [],
23732            indicator;
23733
23734        var that = this;
23735
23736        this.indicators = [];
23737
23738        if ( this.options.scrollbars ) {
23739            // Vertical scrollbar
23740            if ( this.options.scrollY ) {
23741                indicator = {
23742                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
23743                    interactive: interactive,
23744                    defaultScrollbars: true,
23745                    customStyle: customStyle,
23746                    resize: this.options.resizeScrollbars,
23747                    shrink: this.options.shrinkScrollbars,
23748                    fade: this.options.fadeScrollbars,
23749                    listenX: false
23750                };
23751
23752                this.wrapper.appendChild(indicator.el);
23753                indicators.push(indicator);
23754            }
23755
23756            // Horizontal scrollbar
23757            if ( this.options.scrollX ) {
23758                indicator = {
23759                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
23760                    interactive: interactive,
23761                    defaultScrollbars: true,
23762                    customStyle: customStyle,
23763                    resize: this.options.resizeScrollbars,
23764                    shrink: this.options.shrinkScrollbars,
23765                    fade: this.options.fadeScrollbars,
23766                    listenY: false
23767                };
23768
23769                this.wrapper.appendChild(indicator.el);
23770                indicators.push(indicator);
23771            }
23772        }
23773
23774        if ( this.options.indicators ) {
23775            // TODO: check concat compatibility
23776            indicators = indicators.concat(this.options.indicators);
23777        }
23778
23779        for ( var i = indicators.length; i--; ) {
23780            this.indicators.push( new Indicator(this, indicators[i]) );
23781        }
23782
23783        // TODO: check if we can use array.map (wide compatibility and performance issues)
23784        function _indicatorsMap (fn) {
23785            if (that.indicators) {
23786                for ( var i = that.indicators.length; i--; ) {
23787                    fn.call(that.indicators[i]);
23788                }
23789            }
23790        }
23791
23792        if ( this.options.fadeScrollbars ) {
23793            this.on('scrollEnd', function () {
23794                _indicatorsMap(function () {
23795                    this.fade();
23796                });
23797            });
23798
23799            this.on('scrollCancel', function () {
23800                _indicatorsMap(function () {
23801                    this.fade();
23802                });
23803            });
23804
23805            this.on('scrollStart', function () {
23806                _indicatorsMap(function () {
23807                    this.fade(1);
23808                });
23809            });
23810
23811            this.on('beforeScrollStart', function () {
23812                _indicatorsMap(function () {
23813                    this.fade(1, true);
23814                });
23815            });
23816        }
23817
23818
23819        this.on('refresh', function () {
23820            _indicatorsMap(function () {
23821                this.refresh();
23822            });
23823        });
23824
23825        this.on('destroy', function () {
23826            _indicatorsMap(function () {
23827                this.destroy();
23828            });
23829
23830            delete this.indicators;
23831        });
23832    },
23833
23834    _initWheel: function () {
23835        utils.addEvent(this.wrapper, 'wheel', this);
23836        utils.addEvent(this.wrapper, 'mousewheel', this);
23837        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
23838
23839        this.on('destroy', function () {
23840            clearTimeout(this.wheelTimeout);
23841            this.wheelTimeout = null;
23842            utils.removeEvent(this.wrapper, 'wheel', this);
23843            utils.removeEvent(this.wrapper, 'mousewheel', this);
23844            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
23845        });
23846    },
23847
23848    _wheel: function (e) {
23849        if ( !this.enabled ) {
23850            return;
23851        }
23852
23853        var wheelDeltaX, wheelDeltaY,
23854            newX, newY,
23855            that = this;
23856
23857        if ( this.wheelTimeout === undefined ) {
23858            that._execEvent('scrollStart');
23859        }
23860
23861        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
23862        clearTimeout(this.wheelTimeout);
23863        this.wheelTimeout = setTimeout(function () {
23864            if(!that.options.snap) {
23865                that._execEvent('scrollEnd');
23866            }
23867            that.wheelTimeout = undefined;
23868        }, 400);
23869
23870        if ( 'deltaX' in e ) {
23871            if (e.deltaMode === 1) {
23872                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
23873                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
23874            } else {
23875                wheelDeltaX = -e.deltaX;
23876                wheelDeltaY = -e.deltaY;
23877            }
23878        } else if ( 'wheelDeltaX' in e ) {
23879            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
23880            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
23881        } else if ( 'wheelDelta' in e ) {
23882            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
23883        } else if ( 'detail' in e ) {
23884            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
23885        } else {
23886            return;
23887        }
23888
23889        wheelDeltaX *= this.options.invertWheelDirection;
23890        wheelDeltaY *= this.options.invertWheelDirection;
23891
23892        if ( !this.hasVerticalScroll ) {
23893            wheelDeltaX = wheelDeltaY;
23894            wheelDeltaY = 0;
23895        }
23896
23897        if ( this.options.snap ) {
23898            newX = this.currentPage.pageX;
23899            newY = this.currentPage.pageY;
23900
23901            if ( wheelDeltaX > 0 ) {
23902                newX--;
23903            } else if ( wheelDeltaX < 0 ) {
23904                newX++;
23905            }
23906
23907            if ( wheelDeltaY > 0 ) {
23908                newY--;
23909            } else if ( wheelDeltaY < 0 ) {
23910                newY++;
23911            }
23912
23913            this.goToPage(newX, newY);
23914
23915            return;
23916        }
23917
23918        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
23919        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
23920
23921        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
23922        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
23923
23924        if ( newX > 0 ) {
23925            newX = 0;
23926        } else if ( newX < this.maxScrollX ) {
23927            newX = this.maxScrollX;
23928        }
23929
23930        if ( newY > 0 ) {
23931            newY = 0;
23932        } else if ( newY < this.maxScrollY ) {
23933            newY = this.maxScrollY;
23934        }
23935
23936        this.scrollTo(newX, newY, 0);
23937
23938// INSERT POINT: _wheel
23939    },
23940
23941    _initSnap: function () {
23942        this.currentPage = {};
23943
23944        if ( typeof this.options.snap == 'string' ) {
23945            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
23946        }
23947
23948        this.on('refresh', function () {
23949            var i = 0, l,
23950                m = 0, n,
23951                cx, cy,
23952                x = 0, y,
vendor: 7,339 bytes, lines 23953-24206
23953                stepX = this.options.snapStepX || this.wrapperWidth,
23954                stepY = this.options.snapStepY || this.wrapperHeight,
23955                el;
23956
23957            this.pages = [];
23958
23959            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
23960                return;
23961            }
23962
23963            if ( this.options.snap === true ) {
23964                cx = Math.round( stepX / 2 );
23965                cy = Math.round( stepY / 2 );
23966
23967                while ( x > -this.scrollerWidth ) {
23968                    this.pages[i] = [];
23969                    l = 0;
23970                    y = 0;
23971
23972                    while ( y > -this.scrollerHeight ) {
23973                        this.pages[i][l] = {
23974                            x: Math.max(x, this.maxScrollX),
23975                            y: Math.max(y, this.maxScrollY),
23976                            width: stepX,
23977                            height: stepY,
23978                            cx: x - cx,
23979                            cy: y - cy
23980                        };
23981
23982                        y -= stepY;
23983                        l++;
23984                    }
23985
23986                    x -= stepX;
23987                    i++;
23988                }
23989            } else {
23990                el = this.options.snap;
23991                l = el.length;
23992                n = -1;
23993
23994                for ( ; i < l; i++ ) {
23995                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
23996                        m = 0;
23997                        n++;
23998                    }
23999
24000                    if ( !this.pages[m] ) {
24001                        this.pages[m] = [];
24002                    }
24003
24004                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
24005                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
24006                    cx = x - Math.round(el[i].offsetWidth / 2);
24007                    cy = y - Math.round(el[i].offsetHeight / 2);
24008
24009                    this.pages[m][n] = {
24010                        x: x,
24011                        y: y,
24012                        width: el[i].offsetWidth,
24013                        height: el[i].offsetHeight,
24014                        cx: cx,
24015                        cy: cy
24016                    };
24017
24018                    if ( x > this.maxScrollX ) {
24019                        m++;
24020                    }
24021                }
24022            }
24023
24024            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
24025
24026            // Update snap threshold if needed
24027            if ( this.options.snapThreshold % 1 === 0 ) {
24028                this.snapThresholdX = this.options.snapThreshold;
24029                this.snapThresholdY = this.options.snapThreshold;
24030            } else {
24031                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
24032                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
24033            }
24034        });
24035
24036        this.on('flick', function () {
24037            var time = this.options.snapSpeed || Math.max(
24038                    Math.max(
24039                        Math.min(Math.abs(this.x - this.startX), 1000),
24040                        Math.min(Math.abs(this.y - this.startY), 1000)
24041                    ), 300);
24042
24043            this.goToPage(
24044                this.currentPage.pageX + this.directionX,
24045                this.currentPage.pageY + this.directionY,
24046                time
24047            );
24048        });
24049    },
24050
24051    _nearestSnap: function (x, y) {
24052        if ( !this.pages.length ) {
24053            return { x: 0, y: 0, pageX: 0, pageY: 0 };
24054        }
24055
24056        var i = 0,
24057            l = this.pages.length,
24058            m = 0;
24059
24060        // Check if we exceeded the snap threshold
24061        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
24062            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
24063            return this.currentPage;
24064        }
24065
24066        if ( x > 0 ) {
24067            x = 0;
24068        } else if ( x < this.maxScrollX ) {
24069            x = this.maxScrollX;
24070        }
24071
24072        if ( y > 0 ) {
24073            y = 0;
24074        } else if ( y < this.maxScrollY ) {
24075            y = this.maxScrollY;
24076        }
24077
24078        for ( ; i < l; i++ ) {
24079            if ( x >= this.pages[i][0].cx ) {
24080                x = this.pages[i][0].x;
24081                break;
24082            }
24083        }
24084
24085        l = this.pages[i].length;
24086
24087        for ( ; m < l; m++ ) {
24088            if ( y >= this.pages[0][m].cy ) {
24089                y = this.pages[0][m].y;
24090                break;
24091            }
24092        }
24093
24094        if ( i == this.currentPage.pageX ) {
24095            i += this.directionX;
24096
24097            if ( i < 0 ) {
24098                i = 0;
24099            } else if ( i >= this.pages.length ) {
24100                i = this.pages.length - 1;
24101            }
24102
24103            x = this.pages[i][0].x;
24104        }
24105
24106        if ( m == this.currentPage.pageY ) {
24107            m += this.directionY;
24108
24109            if ( m < 0 ) {
24110                m = 0;
24111            } else if ( m >= this.pages[0].length ) {
24112                m = this.pages[0].length - 1;
24113            }
24114
24115            y = this.pages[0][m].y;
24116        }
24117
24118        return {
24119            x: x,
24120            y: y,
24121            pageX: i,
24122            pageY: m
24123        };
24124    },
24125
24126    goToPage: function (x, y, time, easing) {
24127        easing = easing || this.options.bounceEasing;
24128
24129        if ( x >= this.pages.length ) {
24130            x = this.pages.length - 1;
24131        } else if ( x < 0 ) {
24132            x = 0;
24133        }
24134
24135        if ( y >= this.pages[x].length ) {
24136            y = this.pages[x].length - 1;
24137        } else if ( y < 0 ) {
24138            y = 0;
24139        }
24140
24141        var posX = this.pages[x][y].x,
24142            posY = this.pages[x][y].y;
24143
24144        time = time === undefined ? this.options.snapSpeed || Math.max(
24145            Math.max(
24146                Math.min(Math.abs(posX - this.x), 1000),
24147                Math.min(Math.abs(posY - this.y), 1000)
24148            ), 300) : time;
24149
24150        this.currentPage = {
24151            x: posX,
24152            y: posY,
24153            pageX: x,
24154            pageY: y
24155        };
24156
24157        this.scrollTo(posX, posY, time, easing);
24158    },
24159
24160    next: function (time, easing) {
24161        var x = this.currentPage.pageX,
24162            y = this.currentPage.pageY;
24163
24164        x++;
24165
24166        if ( x >= this.pages.length && this.hasVerticalScroll ) {
24167            x = 0;
24168            y++;
24169        }
24170
24171        this.goToPage(x, y, time, easing);
24172    },
24173
24174    prev: function (time, easing) {
24175        var x = this.currentPage.pageX,
24176            y = this.currentPage.pageY;
24177
24178        x--;
24179
24180        if ( x < 0 && this.hasVerticalScroll ) {
24181            x = 0;
24182            y--;
24183        }
24184
24185        this.goToPage(x, y, time, easing);
24186    },
24187
24188    _initKeys: function (e) {
24189        // default key bindings
24190        var keys = {
24191            pageUp: 33,
24192            pageDown: 34,
24193            end: 35,
24194            home: 36,
24195            left: 37,
24196            up: 38,
24197            right: 39,
24198            down: 40
24199        };
24200        var i;
24201
24202        // if you give me characters I give you keycode
24203        if ( typeof this.options.keyBindings == 'object' ) {
24204            for ( i in this.options.keyBindings ) {
24205                if ( typeof this.options.keyBindings[i] == 'string' ) {
24206                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
vendor: 11,097 bytes, lines 24206-24559
24206deAt(0);
24207                }
24208            }
24209        } else {
24210            this.options.keyBindings = {};
24211        }
24212
24213        for ( i in keys ) {
24214            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
24215        }
24216
24217        utils.addEvent(window, 'keydown', this);
24218
24219        this.on('destroy', function () {
24220            utils.removeEvent(window, 'keydown', this);
24221        });
24222    },
24223
24224    _key: function (e) {
24225        if ( !this.enabled ) {
24226            return;
24227        }
24228
24229        var snap = this.options.snap,   // we are using this alot, better to cache it
24230            newX = snap ? this.currentPage.pageX : this.x,
24231            newY = snap ? this.currentPage.pageY : this.y,
24232            now = utils.getTime(),
24233            prevTime = this.keyTime || 0,
24234            acceleration = 0.250,
24235            pos;
24236
24237        if ( this.options.useTransition && this.isInTransition ) {
24238            pos = this.getComputedPosition();
24239
24240            this._translate(Math.round(pos.x), Math.round(pos.y));
24241            this.isInTransition = false;
24242        }
24243
24244        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
24245
24246        switch ( e.keyCode ) {
24247            case this.options.keyBindings.pageUp:
24248                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
24249                    newX += snap ? 1 : this.wrapperWidth;
24250                } else {
24251                    newY += snap ? 1 : this.wrapperHeight;
24252                }
24253                break;
24254            case this.options.keyBindings.pageDown:
24255                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
24256                    newX -= snap ? 1 : this.wrapperWidth;
24257                } else {
24258                    newY -= snap ? 1 : this.wrapperHeight;
24259                }
24260                break;
24261            case this.options.keyBindings.end:
24262                newX = snap ? this.pages.length-1 : this.maxScrollX;
24263                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
24264                break;
24265            case this.options.keyBindings.home:
24266                newX = 0;
24267                newY = 0;
24268                break;
24269            case this.options.keyBindings.left:
24270                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
24271                break;
24272            case this.options.keyBindings.up:
24273                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
24274                break;
24275            case this.options.keyBindings.right:
24276                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
24277                break;
24278            case this.options.keyBindings.down:
24279                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
24280                break;
24281            default:
24282                return;
24283        }
24284
24285        if ( snap ) {
24286            this.goToPage(newX, newY);
24287            return;
24288        }
24289
24290        if ( newX > 0 ) {
24291            newX = 0;
24292            this.keyAcceleration = 0;
24293        } else if ( newX < this.maxScrollX ) {
24294            newX = this.maxScrollX;
24295            this.keyAcceleration = 0;
24296        }
24297
24298        if ( newY > 0 ) {
24299            newY = 0;
24300            this.keyAcceleration = 0;
24301        } else if ( newY < this.maxScrollY ) {
24302            newY = this.maxScrollY;
24303            this.keyAcceleration = 0;
24304        }
24305
24306        this.scrollTo(newX, newY, 0);
24307
24308        this.keyTime = now;
24309    },
24310
24311    _animate: function (destX, destY, duration, easingFn) {
24312        var that = this,
24313            startX = this.x,
24314            startY = this.y,
24315            startTime = utils.getTime(),
24316            destTime = startTime + duration;
24317
24318        function step () {
24319            var now = utils.getTime(),
24320                newX, newY,
24321                easing;
24322
24323            if ( now >= destTime ) {
24324                that.isAnimating = false;
24325                that._translate(destX, destY);
24326
24327                if ( !that.resetPosition(that.options.bounceTime) ) {
24328                    that._execEvent('scrollEnd');
24329                }
24330
24331                return;
24332            }
24333
24334            now = ( now - startTime ) / duration;
24335            easing = easingFn(now);
24336            newX = ( destX - startX ) * easing + startX;
24337            newY = ( destY - startY ) * easing + startY;
24338            that._translate(newX, newY);
24339
24340            if ( that.isAnimating ) {
24341                rAF(step);
24342            }
24343        }
24344
24345        this.isAnimating = true;
24346        step();
24347    },
24348    handleEvent: function (e) {
24349        switch ( e.type ) {
24350            case 'touchstart':
24351            case 'pointerdown':
24352            case 'MSPointerDown':
24353            case 'mousedown':
24354                this._start(e);
24355                break;
24356            case 'touchmove':
24357            case 'pointermove':
24358            case 'MSPointerMove':
24359            case 'mousemove':
24360                this._move(e);
24361                break;
24362            case 'touchend':
24363            case 'pointerup':
24364            case 'MSPointerUp':
24365            case 'mouseup':
24366            case 'touchcancel':
24367            case 'pointercancel':
24368            case 'MSPointerCancel':
24369            case 'mousecancel':
24370                this._end(e);
24371                break;
24372            case 'orientationchange':
24373            case 'resize':
24374                this._resize();
24375                break;
24376            case 'transitionend':
24377            case 'webkitTransitionEnd':
24378            case 'oTransitionEnd':
24379            case 'MSTransitionEnd':
24380                this._transitionEnd(e);
24381                break;
24382            case 'wheel':
24383            case 'DOMMouseScroll':
24384            case 'mousewheel':
24385                this._wheel(e);
24386                break;
24387            case 'keydown':
24388                this._key(e);
24389                break;
24390            case 'click':
24391                if ( this.enabled && !e._constructed ) {
24392                    e.preventDefault();
24393                    e.stopPropagation();
24394                }
24395                break;
24396        }
24397    }
24398};
24399function createDefaultScrollbar (direction, interactive, type) {
24400    var scrollbar = document.createElement('div'),
24401        indicator = document.createElement('div');
24402
24403    if ( type === true ) {
24404        scrollbar.style.cssText = 'position:absolute;z-index:9999';
24405        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';
24406    }
24407
24408    indicator.className = 'iScrollIndicator';
24409
24410    if ( direction == 'h' ) {
24411        if ( type === true ) {
24412            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
24413            indicator.style.height = '100%';
24414        }
24415        scrollbar.className = 'iScrollHorizontalScrollbar';
24416    } else {
24417        if ( type === true ) {
24418            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
24419            indicator.style.width = '100%';
24420        }
24421        scrollbar.className = 'iScrollVerticalScrollbar';
24422    }
24423
24424    scrollbar.style.cssText += ';overflow:hidden';
24425
24426    if ( !interactive ) {
24427        scrollbar.style.pointerEvents = 'none';
24428    }
24429
24430    scrollbar.appendChild(indicator);
24431
24432    return scrollbar;
24433}
24434
24435function Indicator (scroller, options) {
24436    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
24437    this.wrapperStyle = this.wrapper.style;
24438    this.indicator = this.wrapper.children[0];
24439    this.indicatorStyle = this.indicator.style;
24440    this.scroller = scroller;
24441
24442    this.options = {
24443        listenX: true,
24444        listenY: true,
24445        interactive: false,
24446        resize: true,
24447        defaultScrollbars: false,
24448        shrink: false,
24449        fade: false,
24450        speedRatioX: 0,
24451        speedRatioY: 0
24452    };
24453
24454    for ( var i in options ) {
24455        this.options[i] = options[i];
24456    }
24457
24458    this.sizeRatioX = 1;
24459    this.sizeRatioY = 1;
24460    this.maxPosX = 0;
24461    this.maxPosY = 0;
24462
24463    if ( this.options.interactive ) {
24464        if ( !this.options.disableTouch ) {
24465            utils.addEvent(this.indicator, 'touchstart', this);
24466            utils.addEvent(window, 'touchend', this);
24467        }
24468        if ( !this.options.disablePointer ) {
24469            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
24470            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
24471        }
24472        if ( !this.options.disableMouse ) {
24473            utils.addEvent(this.indicator, 'mousedown', this);
24474            utils.addEvent(window, 'mouseup', this);
24475        }
24476    }
24477
24478    if ( this.options.fade ) {
24479        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
24480        var durationProp = utils.style.transitionDuration;
24481        if(!durationProp) {
24482            return;
24483        }
24484        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
24485        // remove 0.0001ms
24486        var self = this;
24487        if(utils.isBadAndroid) {
24488            rAF(function() {
24489                if(self.wrapperStyle[durationProp] === '0.0001ms') {
24490                    self.wrapperStyle[durationProp] = '0s';
24491                }
24492            });
24493        }
24494        this.wrapperStyle.opacity = '0';
24495    }
24496}
24497
24498Indicator.prototype = {
24499    handleEvent: function (e) {
24500        switch ( e.type ) {
24501            case 'touchstart':
24502            case 'pointerdown':
24503            case 'MSPointerDown':
24504            case 'mousedown':
24505                this._start(e);
24506                break;
24507            case 'touchmove':
24508            case 'pointermove':
24509            case 'MSPointerMove':
24510            case 'mousemove':
24511                this._move(e);
24512                break;
24513            case 'touchend':
24514            case 'pointerup':
24515            case 'MSPointerUp':
24516            case 'mouseup':
24517            case 'touchcancel':
24518            case 'pointercancel':
24519            case 'MSPointerCancel':
24520            case 'mousecancel':
24521                this._end(e);
24522                break;
24523        }
24524    },
24525
24526    destroy: function () {
24527        if ( this.options.fadeScrollbars ) {
24528            clearTimeout(this.fadeTimeout);
24529            this.fadeTimeout = null;
24530        }
24531        if ( this.options.interactive ) {
24532            utils.removeEvent(this.indicator, 'touchstart', this);
24533            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
24534            utils.removeEvent(this.indicator, 'mousedown', this);
24535
24536            utils.removeEvent(window, 'touchmove', this);
24537            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
24538            utils.removeEvent(window, 'mousemove', this);
24539
24540            utils.removeEvent(window, 'touchend', this);
24541            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
24542            utils.removeEvent(window, 'mouseup', this);
24543        }
24544
24545        if ( this.options.defaultScrollbars ) {
24546            this.wrapper.parentNode.removeChild(this.wrapper);
24547        }
24548    },
24549
24550    _start: function (e) {
24551        var point = e.touches ? e.touches[0] : e;
24552
24553        e.preventDefault();
24554        e.stopPropagation();
24555
24556        this.transitionTime();
24557
24558        this.initiated = true;
24559        this.moved = false;
vendor: 9,615 bytes, lines 24560-24818
24560        this.lastPointX = point.pageX;
24561        this.lastPointY = point.pageY;
24562
24563        this.startTime  = utils.getTime();
24564
24565        if ( !this.options.disableTouch ) {
24566            utils.addEvent(window, 'touchmove', this);
24567        }
24568        if ( !this.options.disablePointer ) {
24569            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
24570        }
24571        if ( !this.options.disableMouse ) {
24572            utils.addEvent(window, 'mousemove', this);
24573        }
24574
24575        this.scroller._execEvent('beforeScrollStart');
24576    },
24577
24578    _move: function (e) {
24579        var point = e.touches ? e.touches[0] : e,
24580            deltaX, deltaY,
24581            newX, newY,
24582            timestamp = utils.getTime();
24583
24584        if ( !this.moved ) {
24585            this.scroller._execEvent('scrollStart');
24586        }
24587
24588        this.moved = true;
24589
24590        deltaX = point.pageX - this.lastPointX;
24591        this.lastPointX = point.pageX;
24592
24593        deltaY = point.pageY - this.lastPointY;
24594        this.lastPointY = point.pageY;
24595
24596        newX = this.x + deltaX;
24597        newY = this.y + deltaY;
24598
24599        this._pos(newX, newY);
24600
24601// INSERT POINT: indicator._move
24602
24603        e.preventDefault();
24604        e.stopPropagation();
24605    },
24606
24607    _end: function (e) {
24608        if ( !this.initiated ) {
24609            return;
24610        }
24611
24612        this.initiated = false;
24613
24614        e.preventDefault();
24615        e.stopPropagation();
24616
24617        utils.removeEvent(window, 'touchmove', this);
24618        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
24619        utils.removeEvent(window, 'mousemove', this);
24620
24621        if ( this.scroller.options.snap ) {
24622            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
24623
24624            var time = this.options.snapSpeed || Math.max(
24625                    Math.max(
24626                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
24627                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
24628                    ), 300);
24629
24630            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
24631                this.scroller.directionX = 0;
24632                this.scroller.directionY = 0;
24633                this.scroller.currentPage = snap;
24634                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
24635            }
24636        }
24637
24638        if ( this.moved ) {
24639            this.scroller._execEvent('scrollEnd');
24640        }
24641    },
24642
24643    transitionTime: function (time) {
24644        time = time || 0;
24645        var durationProp = utils.style.transitionDuration;
24646        if(!durationProp) {
24647            return;
24648        }
24649
24650        this.indicatorStyle[durationProp] = time + 'ms';
24651
24652        if ( !time && utils.isBadAndroid ) {
24653            this.indicatorStyle[durationProp] = '0.0001ms';
24654            // remove 0.0001ms
24655            var self = this;
24656            rAF(function() {
24657                if(self.indicatorStyle[durationProp] === '0.0001ms') {
24658                    self.indicatorStyle[durationProp] = '0s';
24659                }
24660            });
24661        }
24662    },
24663
24664    transitionTimingFunction: function (easing) {
24665        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
24666    },
24667
24668    refresh: function () {
24669        this.transitionTime();
24670
24671        if ( this.options.listenX && !this.options.listenY ) {
24672            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
24673        } else if ( this.options.listenY && !this.options.listenX ) {
24674            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
24675        } else {
24676            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
24677        }
24678
24679        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
24680            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
24681            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
24682
24683            if ( this.options.defaultScrollbars && this.options.customStyle ) {
24684                if ( this.options.listenX ) {
24685                    this.wrapper.style.right = '8px';
24686                } else {
24687                    this.wrapper.style.bottom = '8px';
24688                }
24689            }
24690        } else {
24691            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
24692            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
24693
24694            if ( this.options.defaultScrollbars && this.options.customStyle ) {
24695                if ( this.options.listenX ) {
24696                    this.wrapper.style.right = '2px';
24697                } else {
24698                    this.wrapper.style.bottom = '2px';
24699                }
24700            }
24701        }
24702
24703        var r = this.wrapper.offsetHeight;  // force refresh
24704
24705        if ( this.options.listenX ) {
24706            this.wrapperWidth = this.wrapper.clientWidth;
24707            if ( this.options.resize ) {
24708                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
24709                this.indicatorStyle.width = this.indicatorWidth + 'px';
24710            } else {
24711                this.indicatorWidth = this.indicator.clientWidth;
24712            }
24713
24714            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
24715
24716            if ( this.options.shrink == 'clip' ) {
24717                this.minBoundaryX = -this.indicatorWidth + 8;
24718                this.maxBoundaryX = this.wrapperWidth - 8;
24719            } else {
24720                this.minBoundaryX = 0;
24721                this.maxBoundaryX = this.maxPosX;
24722            }
24723
24724            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
24725        }
24726
24727        if ( this.options.listenY ) {
24728            this.wrapperHeight = this.wrapper.clientHeight;
24729            if ( this.options.resize ) {
24730                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
24731                this.indicatorStyle.height = this.indicatorHeight + 'px';
24732            } else {
24733                this.indicatorHeight = this.indicator.clientHeight;
24734            }
24735
24736            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
24737
24738            if ( this.options.shrink == 'clip' ) {
24739                this.minBoundaryY = -this.indicatorHeight + 8;
24740                this.maxBoundaryY = this.wrapperHeight - 8;
24741            } else {
24742                this.minBoundaryY = 0;
24743                this.maxBoundaryY = this.maxPosY;
24744            }
24745
24746            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
24747            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
24748        }
24749
24750        this.updatePosition();
24751    },
24752
24753    updatePosition: function () {
24754        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
24755            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
24756
24757        if ( !this.options.ignoreBoundaries ) {
24758            if ( x < this.minBoundaryX ) {
24759                if ( this.options.shrink == 'scale' ) {
24760                    this.width = Math.max(this.indicatorWidth + x, 8);
24761                    this.indicatorStyle.width = this.width + 'px';
24762                }
24763                x = this.minBoundaryX;
24764            } else if ( x > this.maxBoundaryX ) {
24765                if ( this.options.shrink == 'scale' ) {
24766                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
24767                    this.indicatorStyle.width = this.width + 'px';
24768                    x = this.maxPosX + this.indicatorWidth - this.width;
24769                } else {
24770                    x = this.maxBoundaryX;
24771                }
24772            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
24773                this.width = this.indicatorWidth;
24774                this.indicatorStyle.width = this.width + 'px';
24775            }
24776
24777            if ( y < this.minBoundaryY ) {
24778                if ( this.options.shrink == 'scale' ) {
24779                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
24780                    this.indicatorStyle.height = this.height + 'px';
24781                }
24782                y = this.minBoundaryY;
24783            } else if ( y > this.maxBoundaryY ) {
24784                if ( this.options.shrink == 'scale' ) {
24785                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
24786                    this.indicatorStyle.height = this.height + 'px';
24787                    y = this.maxPosY + this.indicatorHeight - this.height;
24788                } else {
24789                    y = this.maxBoundaryY;
24790                }
24791            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
24792                this.height = this.indicatorHeight;
24793                this.indicatorStyle.height = this.height + 'px';
24794            }
24795        }
24796
24797        this.x = x;
24798        this.y = y;
24799
24800        if ( this.scroller.options.useTransform ) {
24801            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
24802        } else {
24803            this.indicatorStyle.left = x + 'px';
24804            this.indicatorStyle.top = y + 'px';
24805        }
24806    },
24807
24808    _pos: function (x, y) {
24809        if ( x < 0 ) {
24810            x = 0;
24811        } else if ( x > this.maxPosX ) {
24812            x = this.maxPosX;
24813        }
24814
24815        if ( y < 0 ) {
24816            y = 0;
24817        } else if ( y > this.maxPosY ) {
24818            y = this.maxPosY;
24819        }
24820
24821        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
24822        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
24823
24824        this.scroller.scrollTo(x, y);
24825    },
24826
24827    fade: function (val, hold) {
24828        if ( hold && !this.visible ) {
24829            return;
24830        }
24831
24832        clearTimeout(this.fadeTimeout);
24833        this.fadeTimeout = null;
24834
24835        var time = val ? 250 : 500,
24836            delay = val ? 0 : 300;
24837
24838        val = val ? '1' : '0';
24839
24840        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
24841
24842        this.fadeTimeout = setTimeout((function (val) {
24843            this.wrapperStyle.opacity = val;
24844            this.visible = +val;
24845        }).bind(this, val), delay);
24846    }
24847};
24848
24849IScroll.utils = utils;
24850
24851if ( typeof module != 'undefined' && module.exports ) {
24852    module.exports = IScroll;
24853} else if ( typeof define == 'function' && define.amd ) {
24854        define( function () { return IScroll; } );
24855} else {
24856    window.IScroll = IScroll;
24857}
24858
24859})(window, document, Math);
24860/*!
24861 * fullPage 2.9.4
24862 * https://github.com/alvarotrigo/fullPage.js
24863 * @license MIT licensed
24864 *
24865 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
24866 */
24867(function(global, factory) {
24868    'use strict';
24869    if (typeof define === 'function' && define.amd) {
24870        define(['jquery'], function($) {
24871          return factory($, global, global.document, global.Math);
24872        });
24873    } else if (typeof exports === "object" && exports) {
24874        module.exports = factory(require('jquery'), global, global.document, global.Math);
24875    } else {
24876        factory(jQuery, global, global.document, global.Math);
24877    }
24878})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
24879    'use strict';
24880
24881    // keeping central set of classnames and selectors
24882    var WRAPPER =               'fullpage-wrapper';
24883    var WRAPPER_SEL =           '.' + WRAPPER;
24884
24885    // slimscroll
24886    var SCROLLABLE =            'fp-scrollable';
24887    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
24888
24889    // util
24890    var RESPONSIVE =            'fp-responsive';
24891    var NO_TRANSITION =         'fp-notransition';
24892    var DESTROYED =             'fp-destroyed';
24893    var ENABLED =               'fp-enabled';
24894    var VIEWING_PREFIX =        'fp-viewing';
24895    var ACTIVE =                'active';
24896    var ACTIVE_SEL =            '.' + ACTIVE;
24897    var COMPLETELY =            'fp-completely';
24898    var COMPLETELY_SEL =        '.' + COMPLETELY;
24899
24900    // section
24901    var SECTION_DEFAULT_SEL =   '.section';
24902    var SECTION =               'fp-section';
24903    var SECTION_SEL =           '.' + SECTION;
24904    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
24905    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
24906    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
24907    var TABLE_CELL =            'fp-tableCell';
24908    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
24909    var AUTO_HEIGHT =           'fp-auto-height';
24910    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
24911    var NORMAL_SCROLL =         'fp-normal-scroll';
24912    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
24913
24914    // section nav
24915    var SECTION_NAV =           'fp-nav';
24916    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
24917    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
24918    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
24919    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
24920
24921    // slide
24922    var SLIDE_DEFAULT_SEL =     '.slide';
24923    var SLIDE =                 'fp-slide';
24924    var SLIDE_SEL =             '.' + SLIDE;
24925    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
24926    var SLIDES_WRAPPER =        'fp-slides';
24927    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
24928    var SLIDES_CONTAINER =      'fp-slidesContainer';
24929    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
24930    var TABLE =                 'fp-table';
24931
24932    // slide nav
24933    var SLIDES_NAV =            'fp-slidesNav';
24934    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
24935    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
24936    var SLIDES_ARROW =          'fp-controlArrow';
24937    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
24938    var SLIDES_PREV =           'fp-prev';
24939    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
24940    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
24941    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
24942    var SLIDES_NEXT =           'fp-next';
24943    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
24944    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
24945    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
24946
24947    var $window = $(window);
24948    var $document = $(document);
24949
24950    // Default options for iScroll.js used when using scrollOverflow
24951    var iscrollOptions = {
24952        scrollbars: true,
24953        mouseWheel: true,
24954        hideScrollbars: false,
24955        fadeScrollbars: false,
24956        disableMouse: true,
24957        interactiveScrollbars: true,
24958        bounce: false,
24959    };
24960
24961    $.fn.fullpage = function(options) {
24962        //only once my friend!
24963        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
24964
24965        // common jQuery objects
24966        var $htmlBody = $('html, body');
24967        var $body = $('body');
24968
24969        var FP = $.fn.fullpage;
24970
24971        // Creating some defaults, extending them with any options that were provided
24972        options = $.extend({
24973            //navigation
24974            menu: false,
24975            anchors:[],
24976            lockAnchors: false,
24977            navigation: false,
24978            navigationPosition: 'right',
24979            navigationTooltips: [],
24980            showActiveTooltip: false,
24981            slidesNavigation: false,
24982            slidesNavPosition: 'bottom',
24983            scrollBar: false,
24984            hybrid: false,
24985
24986            //scrolling
24987            css3: true,
24988            scrollingSpeed: 700,
24989            autoScrolling: true,
24990            fitToSection: true,
24991            fitToSectionDelay: 1000,
24992            easing: 'easeInOutCubic',
24993            easingcss3: 'ease',
24994            loopBottom: false,
24995            loopTop: false,
24996            loopHorizontal: true,
24997            continuousVertical: false,
24998            continuousHorizontal: false,
24999            scrollHorizontally: false,
25000            interlockedSlides: false,
25001            dragAndMove: false,
25002            offsetSections: false,
25003            resetSliders: false,
25004            fadingEffect: false,
25005            normalScrollElements: null,
25006            scrollOverflow: false,
25007            scrollOverflowReset: false,
25008            scrollOverflowHandler: iscrollHandler,
25009            scrollOverflowOptions: null,
25010            touchSensitivity: 5,
25011            normalScrollElementTouchThreshold: 5,
25012            bigSectionsDestination: null,
25013
25014            //Accessibility
25015            keyboardScrolling: true,
25016            animateAnchor: true,
25017            recordHistory: true,
25018
25019            //design
25020            controlArrows: true,
25021            controlArrowColor: '#fff',
25022            verticalCentered: true,
25023            sectionsColor : [],
25024            paddingTop: 0,
25025            paddingBottom: 0,
25026            fixedElements: null,
25027            responsive: 0, //backwards compabitility with responsiveWiddth
25028            responsiveWidth: 0,
25029            responsiveHeight: 0,
25030            responsiveSlides: false,
25031            parallax: false,
25032            parallaxOptions: {
25033                type: 'reveal',
25034                percentage: 62,
25035                property: 'translate'
25036            },
25037
25038            //Custom selectors
25039            sectionSelector: SECTION_DEFAULT_SEL,
25040            slideSelector: SLIDE_DEFAULT_SEL,
25041
25042            //events
25043            afterLoad: null,
25044            onLeave: null,
25045            afterRender: null,
25046            afterResize: null,
25047            afterReBuild: null,
25048            afterSlideLoad: null,
25049            onSlideLeave: null,
25050            afterResponsive: null,
25051
25052            lazyLoading: true
25053        }, options);
25054
25055        //flag to avoid very fast sliding for landscape sliders
25056        var slideMoving = false;
25057
25058        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
25059        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
25060        var container = $(this);
25061        var windowsHeight = $window.height();
25062        var isResizing = false;
25063        var isWindowFocused = true;
25064        var lastScrolledDestiny;
25065        var lastScrolledSlide;
25066        var canScroll = true;
25067        var scrollings = [];
25068        var controlPressed;
25069        var startingSection;
25070        var isScrollAllowed = {};
25071        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
25072        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
25073        var MSPointer = getMSPointer();
25074        var events = {
25075            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
25076            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
25077        };
25078
25079        //cheks for passive event support
25080        //added by Uncode from new fullPage updates
25081        var g_supportsPassive = false;
25082        try {
25083          var opts = Object.defineProperty({}, 'passive', {
25084            get: function() {
25085              g_supportsPassive = true;
25086            }
25087          });
25088          window.addEventListener("testPassive", null, opts);
25089          window.removeEventListener("testPassive", null, opts);
25090        } catch (e) {}
25091
25092        //timeouts
25093        var resizeId;
25094        var afterSectionLoadsId;
25095        var afterSlideLoadsId;
25096        var scrollId;
25097        var scrollId2;
25098        var keydownId;
25099        var originals = $.extend(true, {}, options); //deep copy
25100
25101        //Uncode addition
25102        var $masthead = $('#masthead');
25103        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
25104        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
25105        var bodyBorder = UNCODE.bodyBorder;
25106        var adminBarHeight = UNCODE.adminBarHeight;
25107
25108        displayWarnings();
25109
25110        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
25111        iscrollOptions.click = isTouch; // see #2035
25112
25113        //extending iScroll options with the user custom ones
25114        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
25115
25116        //easeInOutCubic animation included in the plugin
25117        $.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;}});
25118
25119        /**
25120        * Sets the autoScroll option.
25121        * It changes the scroll bar visibility and the history of the site as a result.
25122        */
25123        function setAutoScrolling(value, type){
25124            //removing the transformation
25125            if(!value){
25126                silentScroll(0);
25127            }
25128
25129            setVariableState('autoScrolling', value, type);
25130
25131            var element = $(SECTION_ACTIVE_SEL);
25132
25133            if(options.autoScrolling && !options.scrollBar){
25134                $htmlBody.css({
25135                    'overflow' : 'hidden !important',
25136                    'height' : '100%'
25137                });
25138
25139                //Uncode addition
25140                //setRecordHistory(originals.recordHistory, 'internal');
25141
25142                //for IE touch devices
25143                container.css({
25144                    '-ms-touch-action': 'none',
25145                    'touch-action': 'none'
25146                });
25147
25148                if(element.length){
25149                    //moving the container up
25150                    silentScroll(element.position().top);
25151                }
25152
25153            }else{
25154                $htmlBody.css({
25155                    'overflow' : 'visible !important',
25156                    'height' : 'initial'
25157                });
25158
25159                //Uncode addition
25160                //setRecordHistory(false, 'internal');
25161
25162                //for IE touch devices
25163                container.css({
25164                    '-ms-touch-action': '',
25165                    'touch-action': ''
25166                });
25167
25168                //scrolling the page to the section with no animation
25169                if (element.length) {
25170                    $htmlBody.scrollTop(element.position().top);
25171                }
25172            }
25173        }
25174
25175        /**
25176        * Defines wheter to record the history for each hash change in the URL.
25177        */
25178        function setRecordHistory(value, type){
25179            setVariableState('recordHistory', value, type);
25180        }
25181
25182        /**
25183        * Defines the scrolling speed
25184        */
25185        function setScrollingSpeed(value, type){
25186            setVariableState('scrollingSpeed', value, type);
25187        }
25188
25189        /**
25190        * Sets fitToSection
25191        */
25192        function setFitToSection(value, type){
25193            setVariableState('fitToSection', value, type);
25194        }
25195
25196        /**
25197        * Sets lockAnchors
25198        */
25199        function setLockAnchors(value){
25200            options.lockAnchors = value;
25201        }
25202
25203        /**
25204        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
25205        */
25206        function setMouseWheelScrolling(value){
25207            if(value){
25208                addMouseWheelHandler();
25209                addMiddleWheelHandler();
25210            }else{
25211                removeMouseWheelHandler();
25212                removeMiddleWheelHandler();
25213            }
25214        }
25215
25216        /**
25217        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
25218        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
25219        *
25220        * @param directions string containing the direction or directions separated by comma.
25221        */
25222        function setAllowScrolling(value, directions){
25223            if(typeof directions !== 'undefined'){
25224                directions = directions.replace(/ /g,'').split(',');
25225
25226                $.each(directions, function (index, direction){
25227                    setIsScrollAllowed(value, direction, 'm');
25228                });
25229            }
25230            else if(value){
25231                setMouseWheelScrolling(true);
25232                addTouchHandler();
25233            }else{
25234                setMouseWheelScrolling(false);
25235                removeTouchHandler();
25236            }
25237        }
25238
25239        /**
25240        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
25241        */
25242        function setKeyboardScrolling(value, directions){
25243            if(typeof directions !== 'undefined'){
25244                directions = directions.replace(/ /g,'').split(',');
25245
25246                $.each(directions, function (index, direction){
25247                    setIsScrollAllowed(value, direction, 'k');
25248                });
25249            }else{
25250                options.keyboardScrolling = value;
25251            }
25252        }
25253
25254        /**
25255        * Moves the page up one section.
25256        */
25257        function moveSectionUp(){
25258            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
25259
25260            //looping to the bottom if there's no more sections above
25261            if (!prev.length && (options.loopTop || options.continuousVertical)) {
25262                prev = $(SECTION_SEL).last();
25263            }
25264
25265            if (prev.length) {
25266                scrollPage(prev, null, true);
25267            }
25268        }
25269
25270        /**
25271        * Moves the page down one section.
25272        */
25273        function moveSectionDown(){
25274            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
25275
25276            //looping to the top if there's no more sections below
25277            if(!next.length &&
25278                (options.loopBottom || options.continuousVertical)){
25279                next = $(SECTION_SEL).first();
25280            }
25281
25282            if(next.length){
25283                scrollPage(next, null, false);
25284            }
25285        }
25286
25287        /**
25288        * Moves the page to the given section and slide with no animation.
25289        * Anchors or index positions can be used as params.
25290        */
25291        function silentMoveTo(sectionAnchor, slideAnchor){
25292            setScrollingSpeed (0, 'internal');
25293            moveTo(sectionAnchor, slideAnchor);
25294            setScrollingSpeed (originals.scrollingSpeed, 'internal');
25295        }
25296
25297        /**
25298        * Moves the page to the given section and slide.
25299        * Anchors or index positions can be used as params.
25300        */
25301        function moveTo(sectionAnchor, slideAnchor){
25302            var destiny = getSectionByAnchor(sectionAnchor);
25303
25304            if (typeof slideAnchor !== 'undefined'){
25305                scrollPageAndSlide(sectionAnchor, slideAnchor);
25306            }else if(destiny.length > 0){
25307                scrollPage(destiny);
25308            }
25309        }
25310
25311        /**
25312        * Slides right the slider of the active section.
25313        * Optional `section` param.
25314        */
25315        function moveSlideRight(section){
25316            moveSlide('right', section);
25317        }
25318
25319        /**
25320        * Slides left the slider of the active section.
25321        * Optional `section` param.
25322        */
25323        function moveSlideLeft(section){
25324            moveSlide('left', section);
25325        }
25326
25327        /**
25328         * When resizing is finished, we adjust the slides sizes and positions
25329         */
25330        function reBuild(resizing){
25331            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
25332
25333            isResizing = true;
25334
25335            windowsHeight = $window.height();  //updating global var
25336
25337            $(SECTION_SEL).each(function(){
25338                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
25339                var slides = $(this).find(SLIDE_SEL);
25340
25341                //adjusting the height of the table-cell for IE and Firefox
25342                if(options.verticalCentered){
25343                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
25344                }
25345
25346                $(this).css('height', windowsHeight + 'px');
25347
25348                //resizing the scrolling divs
25349                if(options.scrollOverflow){
25350                    if(slides.length){
25351                        slides.each(function(){
25352                            createScrollBar($(this));
25353                        });
25354                    }else{
25355                        createScrollBar($(this));
25356                    }
25357                }
25358
25359                //adjusting the position fo the FULL WIDTH slides...
25360                if (slides.length > 1) {
25361                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
25362                }
25363            });
25364
25365            var activeSection = $(SECTION_ACTIVE_SEL);
25366            var sectionIndex = activeSection.index(SECTION_SEL);
25367
25368            //isn't it the first section?
25369            if(sectionIndex){
25370                //adjusting the position for the current section
25371                silentMoveTo(sectionIndex + 1);
25372            }
25373
25374            isResizing = false;
25375            // Uncode change
25376            // $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
25377            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container, getTableHeight());
25378            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
25379        }
25380
25381        /**
25382        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
25383        * are smaller than the set limit values.
25384        */
25385        function setResponsive(active){
25386            var isResponsive = $body.hasClass(RESPONSIVE);
25387
25388            if(active){
25389                if(!isResponsive){
25390                    setAutoScrolling(false, 'internal');
25391                    setFitToSection(false, 'internal');
25392                    $(SECTION_NAV_SEL).hide();
25393                    $body.addClass(RESPONSIVE);
25394                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
25395                }
25396            }
25397            else if(isResponsive){
25398                setAutoScrolling(originals.autoScrolling, 'internal');
25399                setFitToSection(originals.autoScrolling, 'internal');
25400                $(SECTION_NAV_SEL).show();
25401                $body.removeClass(RESPONSIVE);
25402                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
25403            }
25404        }
25405
25406        if($(this).length){
25407            //public functions
25408            FP.setAutoScrolling = setAutoScrolling;
25409            FP.setRecordHistory = setRecordHistory;
25410            FP.setScrollingSpeed = setScrollingSpeed;
25411            FP.setFitToSection = setFitToSection;
25412            FP.setLockAnchors = setLockAnchors;
25413            FP.setMouseWheelScrolling = setMouseWheelScrolling;
25414            FP.setAllowScrolling = setAllowScrolling;
25415            FP.setKeyboardScrolling = setKeyboardScrolling;
25416            FP.moveSectionUp = moveSectionUp;
25417            FP.moveSectionDown = moveSectionDown;
25418            FP.silentMoveTo = silentMoveTo;
25419            FP.moveTo = moveTo;
25420            FP.moveSlideRight = moveSlideRight;
25421            FP.moveSlideLeft = moveSlideLeft;
25422            FP.fitToSection = fitToSection;
25423            FP.reBuild = reBuild;
25424            FP.setResponsive = setResponsive;
25425            FP.destroy = destroy;
25426
25427            init();
25428
25429            bindEvents();
25430        }
25431
25432        function init(){
25433            //if css3 is not supported, it will use jQuery animations
25434            if(options.css3){
25435                options.css3 = support3d();
25436            }
25437
25438            options.scrollBar = options.scrollBar || options.hybrid;
25439
25440            setOptionsFromDOM();
25441            prepareDom();
25442            setAllowScrolling(true);
25443            setAutoScrolling(options.autoScrolling, 'internal');
25444            responsive();
25445
25446            //setting the class for the body element
25447            setBodyClass();
25448
25449            //Uncode addition
25450            // if(document.readyState === 'complete'){
25451            //     scrollToAnchor();
25452            // }
25453            // $window.on('load', scrollToAnchor);
25454        }
25455
25456        function bindEvents(){
25457            $window
25458                //when scrolling...
25459                //.on('scroll', scrollHandler)
25460
25461                //detecting any change on the URL to scroll to the given anchor link
25462                //(a way to detect back history button as we play with the hashes on the URL)
25463                .on('hashchange', hashChangeHandler)
25464
25465                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
25466                .blur(blurHandler)
25467
25468                //when resizing the site, we adjust the heights of the sections, slimScroll...
25469                .resize(resizeHandler);
25470
25471            $document
25472                //Sliding with arrow keys, both, vertical and horizontal
25473                .keydown(keydownHandler)
25474
25475                //to prevent scrolling while zooming
25476                .keyup(keyUpHandler)
25477
25478                //Scrolls to the section when clicking the navigation bullet
25479                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
25480
25481                //Scrolls the slider to the given slide destination for the given section
25482                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
25483
25484                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
25485
25486            //Scrolling horizontally when clicking on the slider controls.
25487            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
25488
25489            /**
25490            * Applying normalScroll elements.
25491            * Ignoring the scrolls over the specified selectors.
25492            */
25493            if(options.normalScrollElements){
25494                $document.on('mouseenter', options.normalScrollElements, function () {
25495                    setMouseWheelScrolling(false);
25496                });
25497
25498                $document.on('mouseleave', options.normalScrollElements, function(){
25499                    setMouseWheelScrolling(true);
25500                });
25501            }
25502        }
25503
25504        /**
25505        * Setting options from DOM elements if they are not provided.
25506        */
25507        function setOptionsFromDOM(){
25508            var sections = container.find(options.sectionSelector);
25509
25510            //no anchors option? Checking for them in the DOM attributes
25511            if(!options.anchors.length){
25512                options.anchors = sections.filter('[data-anchor]').map(function(){
25513                    return $(this).data('anchor').toString();
25514                }).get();
25515            }
25516
25517            //no tooltips option? Checking for them in the DOM attributes
25518            if(!options.navigationTooltips.length){
25519                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
25520                    return $(this).data('tooltip').toString();
25521                }).get();
25522            }
25523        }
25524
25525        /**
25526        * Works over the DOM structure to set it up for the current fullpage options.
25527        */
25528        function prepareDom(){
25529            container.css({
25530                'height': '100%',
25531                'position': 'relative'
25532            });
25533
25534            //adding a class to recognize the container internally in the code
25535            container.addClass(WRAPPER);
25536            $('html').addClass(ENABLED);
25537
25538            windowsHeight = $window.height();
25539
25540            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
25541
25542            addInternalSelectors();
25543
25544             //styling the sections / slides / menu
25545            $(SECTION_SEL).each(function(index){
25546                var section = $(this);
25547                var slides = section.find(SLIDE_SEL);
25548                var numSlides = slides.length;
25549
25550                styleSection(section, index);
25551                styleMenu(section, index);
25552
25553                // if there's any slide
25554                if (numSlides > 0) {
25555                    styleSlides(section, slides, numSlides);
25556                }else{
25557                    if(options.verticalCentered){
25558                        addTableClass(section);
25559                    }
25560                }
25561            });
25562
25563            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
25564            if(options.fixedElements && options.css3){
25565                $(options.fixedElements).appendTo($body);
25566            }
25567
25568            //vertical centered of the navigation + active bullet
25569            if(options.navigation){
25570                addVerticalNavigation();
25571            }
25572
25573            enableYoutubeAPI();
25574
25575            if(options.scrollOverflow){
25576                if(document.readyState === 'complete'){
25577                    createScrollBarHandler();
25578                }
25579                //after DOM and images are loaded
25580                $window.on('load', createScrollBarHandler);
25581            }else{
25582                afterRenderActions();
25583            }
25584        }
25585
25586        /**
25587        * Styles the horizontal slides for a section.
25588        */
25589        function styleSlides(section, slides, numSlides){
25590            var sliderWidth = numSlides * 100;
25591            var slideWidth = 100 / numSlides;
25592
25593            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
25594            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
25595
25596            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
25597
25598            if(numSlides > 1){
25599                if(options.controlArrows){
25600                    createSlideArrows(section);
25601                }
25602
25603                if(options.slidesNavigation){
25604                    addSlidesNavigation(section, numSlides);
25605                }
25606            }
25607
25608            slides.each(function(index) {
25609                $(this).css('width', slideWidth + '%');
25610
25611                if(options.verticalCentered){
25612                    addTableClass($(this));
25613                }
25614            });
25615
25616            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
25617
25618            //if the slide won't be an starting point, the default will be the first one
25619            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
25619ide by default.
25620            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
25621                silentLandscapeScroll(startingSlide, 'internal');
25622            }else{
25623                slides.eq(0).addClass(ACTIVE);
25624            }
25625        }
25626
25627        /**
25628        * Styling vertical sections
25629        */
25630        function styleSection(section, index){
25631            //if no active section is defined, the 1st one will be the default one
25632            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
25633                section.addClass(ACTIVE);
25634            }
25635            startingSection = $(SECTION_ACTIVE_SEL);
25636
25637            section.css('height', windowsHeight + 'px');
25638
25639            if(options.paddingTop){
25640                section.css('padding-top', options.paddingTop);
25641            }
25642
25643            if(options.paddingBottom){
25644                section.css('padding-bottom', options.paddingBottom);
25645            }
25646
25647            if (typeof options.sectionsColor[index] !==  'undefined') {
25648                section.css('background-color', options.sectionsColor[index]);
25649            }
25650
25651            if (typeof options.anchors[index] !== 'undefined') {
25652                section.attr('data-anchor', options.anchors[index]);
25653            }
25654        }
25655
25656        /**
25657        * Sets the data-anchor attributes to the menu elements and activates the current one.
25658        */
25659        function styleMenu(section, index){
25660            if (typeof options.anchors[index] !== 'undefined') {
25661                //activating the menu / nav element on load
25662                if(section.hasClass(ACTIVE)){
25663                    activateMenuAndNav(options.anchors[index], index);
25664                }
25665            }
25666
25667            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
25668            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
25669                $(options.menu).appendTo($body);
25670            }
25671        }
25672
25673        /**
25674        * Adds internal classes to be able to provide customizable selectors
25675        * keeping the link with the style sheet.
25676        */
25677        function addInternalSelectors(){
25678            container.find(options.sectionSelector).addClass(SECTION);
25679            container.find(options.slideSelector).addClass(SLIDE);
25680        }
25681
25682        /**
25683        * Creates the control arrows for the given section
25684        */
25685        function createSlideArrows(section){
25686            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
25687
25688            if(options.controlArrowColor!='#fff'){
25689                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
25690                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
25691            }
25692
25693            if(!options.loopHorizontal){
25694                section.find(SLIDES_ARROW_PREV_SEL).hide();
25695            }
25696        }
25697
25698        /**
25699        * Creates a vertical navigation bar.
25700        */
25701        function addVerticalNavigation(){
25702            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
25703            var nav = $(SECTION_NAV_SEL);
25704
25705            nav.addClass(function() {
25706                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
25707            });
25708
25709            for (var i = 0; i < $(SECTION_SEL).length; i++) {
25710                var link = '';
25711                if (options.anchors.length) {
25712                    link = options.anchors[i];
25713                }
25714
25715                var li = '<li><a href="#' + link + '"><span></span></a>';
25716
25717                // Only add tooltip if needed (defined by user)
25718                var tooltip = options.navigationTooltips[i];
25719
25720                if (typeof tooltip !== 'undefined' && tooltip !== '') {
25721                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
25722                }
25723
25724                li += '</li>';
25725
25726                nav.find('ul').append(li);
25727            }
25728
25729            //centering it vertically
25730            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
25731
25732            //activating the current active section
25733            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
25734        }
25735
25736        /**
25737        * Creates the slim scroll scrollbar for the sections and slides inside them.
25738        */
25739        function createScrollBarHandler(){
25740            $(SECTION_SEL).each(function(){
25741                var slides = $(this).find(SLIDE_SEL);
25742
25743                if(slides.length){
25744                    slides.each(function(){
25745                        createScrollBar($(this));
25746                    });
25747                }else{
25748                    createScrollBar($(this));
25749                }
25750
25751            });
25752            afterRenderActions();
25753        }
25754
25755        /*
25756        * Enables the Youtube videos API so we can control their flow if necessary.
25757        */
25758        function enableYoutubeAPI(){
25759            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
25760                addURLParam($(this), 'enablejsapi=1');
25761            });
25762        }
25763
25764        /**
25765        * Adds a new parameter and its value to the `src` of a given element
25766        */
25767        function addURLParam(element, newParam){
25768            var originalSrc = element.attr('src');
25769            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
25770        }
25771
25772        /*
25773        * Returns the prefix sign to use for a new parameter in an existen URL.
25774        *
25775        * @return {String}  ? | &
25776        */
25777        function getUrlParamSign(url){
25778            return ( !/\?/.test( url ) ) ? '?' : '&';
25779        }
25780
25781        /**
25782        * Actions and callbacks to fire afterRender
25783        */
25784        function afterRenderActions(){
25785            var section = $(SECTION_ACTIVE_SEL);
25786
25787            section.addClass(COMPLETELY);
25788
25789            if(options.scrollOverflowHandler.afterRender){
25790                options.scrollOverflowHandler.afterRender(section);
25791            }
25792            lazyLoad(section);
25793            playMedia(section);
25794            options.scrollOverflowHandler.afterLoad();
25795
25796            if(isDestinyTheStartingSection()){
25797                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
25798            }
25799
25800            // Uncode change
25801            // $.isFunction( options.afterRender ) && options.afterRender.call(container);
25802            $.isFunction( options.afterRender ) && options.afterRender.call(container, getTableHeight());
25803        }
25804
25805        /**
25806        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
25807        */
25808        function isDestinyTheStartingSection(){
25809            var anchors =  window.location.hash.replace('#', '').split('/');
25810            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
25811
25812            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
25813        }
25814
25815
25816        var isScrolling = false;
25817        var lastScroll = 0;
25818
25819        //when scrolling...
25820        function scrollHandler(){
25821            var currentSection;
25822
25823            if(!options.autoScrolling || options.scrollBar){
25824                var currentScroll = $window.scrollTop();
25825                var scrollDirection = getScrollDirection(currentScroll);
25826                var visibleSectionIndex = 0;
25827                var screen_mid = currentScroll + ($window.height() / 2.0);
25828                var isAtBottom = $body.height() - $window.height() === currentScroll;
25829                var sections =  document.querySelectorAll(SECTION_SEL);
25830
25831                //when using `auto-height` for a small last section it won't be centered in the viewport
25832                if(isAtBottom){
25833                    visibleSectionIndex = sections.length - 1;
25834                }
25835                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
25836                else if(!currentScroll){
25837                    visibleSectionIndex = 0;
25838                }
25839
25840                //taking the section which is showing more content in the viewport
25841                else{
25842                    for (var i = 0; i < sections.length; ++i) {
25843                        var section = sections[i];
25844
25845                        // Pick the the last section which passes the middle line of the screen.
25846                        if (section.offsetTop <= screen_mid)
25847                        {
25848                            visibleSectionIndex = i;
25849                        }
25850                    }
25851                }
25852
25853                if(isCompletelyInViewPort(scrollDirection)){
25854                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
25855                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
25856                    }
25857                }
25858
25859                //geting the last one, the current one on the screen
25860                currentSection = $(sections).eq(visibleSectionIndex);
25861
25862                //setting the visible section as active when manually scrolling
25863                //executing only once the first time we reach the section
25864                if(!currentSection.hasClass(ACTIVE)){
25865                    isScrolling = true;
25866                    var leavingSection = $(SECTION_ACTIVE_SEL);
25867                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
25868                    var yMovement = getYmovement(currentSection);
25869                    var anchorLink  = currentSection.data('anchor');
25870                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
25871                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
25872                    var slideIndex;
25873                    var slideAnchorLink;
25874
25875                    if(activeSlide.length){
25876                        slideAnchorLink = activeSlide.data('anchor');
25877                        slideIndex = activeSlide.index();
25878                    }
25879
25880                    if(canScroll){
25881                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
25882
25883                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
25884                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
25885
25886                        stopMedia(leavingSection);
25887                        lazyLoad(currentSection);
25888                        playMedia(currentSection);
25889
25890                        activateMenuAndNav(anchorLink, sectionIndex - 1);
25891
25892                        if(options.anchors.length){
25893                            //needed to enter in hashChange event when using the menu with anchor links
25894                            lastScrolledDestiny = anchorLink;
25895                        }
25896                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
25897                    }
25898
25899                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
25900                    clearTimeout(scrollId);
25901                    scrollId = setTimeout(function(){
25902                        isScrolling = false;
25903                    }, 100);
25904                }
25905
25906                if(options.fitToSection){
25907                    //for the auto adjust of the viewport to fit a whole section
25908                    clearTimeout(scrollId2);
25909
25910                    scrollId2 = setTimeout(function(){
25911                        //checking it again in case it changed during the delay
25912                        if(options.fitToSection){
25913                            fitToSection();
25914                        }
25915                    }, options.fitToSectionDelay);
25916                }
25917            }
25918        }
25919
25920        /**
25921        * Fits the site to the nearest active section
25922        */
25923        function fitToSection(){
25924            //checking fitToSection again in case it was set to false before the timeout delay
25925            if(canScroll){
25926                //allows to scroll to an active section and
25927                //if the section is already active, we prevent firing callbacks
25928                isResizing = true;
25929
25930                scrollPage($(SECTION_ACTIVE_SEL));
25931                isResizing = false;
25932            }
25933        }
25934
25935        /**
25936        * Determines whether the active section has seen in its whole or not.
25937        */
25938        function isCompletelyInViewPort(movement){
25939            var top = $(SECTION_ACTIVE_SEL).position().top;
25940            var bottom = top + $window.height();
25941
25942            if(movement == 'up'){
25943                return bottom >= ($window.scrollTop() + $window.height());
25944            }
25945            return top <= $window.scrollTop();
25946        }
25947
25948        /**
25949        * Gets the directon of the the scrolling fired by the scroll event.
25950        */
25951        function getScrollDirection(currentScroll){
25952            var direction = currentScroll > lastScroll ? 'down' : 'up';
25953
25954            lastScroll = currentScroll;
25955
25956            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
25957            previousDestTop = currentScroll;
25958
25959            return direction;
25960        }
25961
25962        /**
25963        * Determines the way of scrolling up or down:
25964        * by 'automatically' scrolling a section or by using the default and normal scrolling.
25965        */
25966        function scrolling(type, scrollable){
25967            if (!isScrollAllowed.m[type]){
25968                return;
25969            }
25970            var check = (type === 'down') ? 'bottom' : 'top';
25971            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
25972
25973            if(scrollable.length > 0 ){
25974                //is the scrollbar at the start/end of the scroll?
25975                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
25976                    scrollSection();
25977                }else{
25978                    return true;
25979                }
25980            }else{
25981                // moved up/down
25982                scrollSection();
25983            }
25984        }
25985
25986        /*
25987        * Preventing bouncing in iOS #2285
25988        */
25989        function preventBouncing(event){
25990            var e = event.originalEvent;
25991            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){
25992                //preventing the easing on iOS devices
25993                event.preventDefault();
25994            }
25995        }
25996
25997        var touchStartY = 0;
25998        var touchStartX = 0;
25999        var touchEndY = 0;
26000        var touchEndX = 0;
26001
26002        /* Detecting touch events
26003
26004        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
26005        * This way, the touchstart and the touch moves shows an small difference between them which is the
26006        * used one to determine the direction.
26007        */
26008        function touchMoveHandler(event){
26009            var e = event.originalEvent;
26010            var activeSection = $(e.target).closest(SECTION_SEL);
26011
26012            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
26013            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
26014
26015                if(options.autoScrolling){
26016                    //preventing the easing on iOS devices
26017                    event.preventDefault();
26018                }
26019
26020                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
26021                var touchEvents = getEventsPage(e);
26022
26023                touchEndY = touchEvents.y;
26024                touchEndX = touchEvents.x;
26025
26026                //if movement in the X axys is greater than in the Y and the currect section has slides...
26027                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
26028
26029                    //is the movement greater than the minimum resistance to scroll?
26030                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
26031                        if (touchStartX > touchEndX) {
26032                            if(isScrollAllowed.m.right){
26033                                moveSlideRight(activeSection); //next
26034                            }
26035                        } else {
26036                            if(isScrollAllowed.m.left){
26037                                moveSlideLeft(activeSection); //prev
26038                            }
26039                        }
26040                    }
26041                }
26042
26043                //vertical scrolling (only when autoScrolling is enabled)
26044                else if(options.autoScrolling && canScroll){
26045
26046                    //is the movement greater than the minimum resistance to scroll?
26047                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
26048                        if (touchStartY > touchEndY) {
26049                            scrolling('down', scrollable);
26050                        } else if (touchEndY > touchStartY) {
26051                            scrolling('up', scrollable);
26052                        }
26053                    }
26054                }
26055            }
26056        }
26057
26058        /**
26059         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
26060         * Currently works well for iOS - Android might need some testing
26061         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
26062         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
26063         * @return {boolean} true if there is a match to options.normalScrollElements
26064         */
26065        function checkParentForNormalScrollElement (el, hop) {
26066            hop = hop || 0;
26067            var parent = $(el).parent();
26068
26069            if (hop < options.normalScrollElementTouchThreshold &&
26070                parent.is(options.normalScrollElements) ) {
26071                return true;
26072            } else if (hop == options.normalScrollElementTouchThreshold) {
26073                return false;
26074            } else {
26075                return checkParentForNormalScrollElement(parent, ++hop);
26076            }
26077        }
26078
26079        /**
26080        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
26081        * this way we make sure that is really a touch event what IE is detecting.
26082        */
26083        function isReallyTouch(e){
26084            //if is not IE   ||  IE is detecting `touch` or `pen`
26085            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
26086        }
26087
26088        /**
26089        * Handler for the touch start event.
26090        */
26091        function touchStartHandler(event){
26092            var e = event.originalEvent;
26093
26094            //stopping the auto scroll to adjust to a section
26095            if(options.fitToSection){
26096                $htmlBody.stop();
26097            }
26098
26099            if(isReallyTouch(e)){
26100                var touchEvents = getEventsPage(e);
26101                touchStartY = touchEvents.y;
26102                touchStartX = touchEvents.x;
26103            }
26104        }
26105
26106        /**
26107        * Gets the average of the last `number` elements of the given array.
26108        */
26109        function getAverage(elements, number){
26110            var sum = 0;
26111
26112            //taking `number` elements from the end to make the average, if there are not enought, 1
26113            var lastElements = elements.slice(Math.max(elements.length - number, 1));
26114
26115            for(var i = 0; i < lastElements.length; i++){
26116                sum = sum + lastElements[i];
26117            }
26118
26119            return Math.ceil(sum/number);
26120        }
26121
26122        /**
26123         * Detecting mousewheel scrolling
26124         *
26125         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
26126         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
26127         */
26128        var prevTime = new Date().getTime();
26129
26130        function MouseWheelHandler(e) {
26131            var curTime = new Date().getTime();
26132            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
26133
26134            //autoscrolling and not zooming?
26135            if(options.autoScrolling && !controlPressed && !isNormalScroll){
26136                // cross-browser wheel delta
26137                e = e || window.event;
26138                var value = e.wheelDelta || -e.deltaY || -e.detail;
26139                var delta = Math.max(-1, Math.min(1, value));
26140
26141                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
26142                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
26143
26144                //Limiting the array to 150 (lets not waste memory!)
26145                if(scrollings.length > 149){
26146                    scrollings.shift();
26147                }
26148
26149                //keeping record of the previous scrollings
26150                scrollings.push(Math.abs(value));
26151
26152                //preventing to scroll the site on mouse wheel when scrollbar is present
26153                if(options.scrollBar){
26154                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
26155                }
26156
26157                var activeSection = $(SECTION_ACTIVE_SEL);
26158                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
26159
26160                //time difference between the last scroll and the current one
26161                var timeDiff = curTime-prevTime;
26162                prevTime = curTime;
26163
26164                //haven't they scrolled in a while?
26165                //(enough to be consider a different scrolling action to scroll another section)
26166                if(timeDiff > 200){
26167                    //emptying the array, we dont care about old scrollings for our averages
26168                    scrollings = [];
26169                }
26170
26171                if(canScroll){
26172                    var averageEnd = getAverage(scrollings, 10);
26173                    var averageMiddle = getAverage(scrollings, 70);
26174                    var isAccelerating = averageEnd >= averageMiddle;
26175
26176                    //to avoid double swipes...
26177                    if(isAccelerating && isScrollingVertically){
26178                        //scrolling down?
26179                        if (delta < 0) {
26180                            scrolling('down', scrollable);
26181
26182                        //scrolling up?
26183                        }else {
26184                            scrolling('up', scrollable);
26185                        }
26186                    }
26187                }
26188
26189                return false;
26190            }
26191
26192            if(options.fitToSection){
26193                //stopping the auto scroll to adjust to a section
26194                $htmlBody.stop();
26195            }
26196        }
26197
26198        /**
26199        * Slides a slider to the given direction.
26200        * Optional `section` param.
26201        */
26202        function moveSlide(direction, section){
26203            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
26204            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
26205            var numSlides = slides.find(SLIDE_SEL).length;
26206
26207            // more than one slide needed and nothing should be sliding
26208            if (!slides.length || slideMoving || numSlides < 2) {
26209                return;
26210            }
26211
26212            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
26213            var destiny = null;
26214
26215            if(direction === 'left'){
26216                destiny = currentSlide.prev(SLIDE_SEL);
26217            }else{
26218                destiny = currentSlide.next(SLIDE_SEL);
26219            }
26220
26221            //isn't there a next slide in the secuence?
26222            if(!destiny.length){
26223                //respect loopHorizontal settin
26224                if (!options.loopHorizontal) return;
26225
26226                if(direction === 'left'){
26227                    destiny = currentSlide.siblings(':last');
26228                }else{
26229                    destiny = currentSlide.siblings(':first');
26230                }
26231            }
26232
26233            slideMoving = true;
26234
26235            landscapeScroll(slides, destiny, direction);
26236        }
26237
26238        /**
26239        * Maintains the active slides in the viewport
26240        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
26241        */
26242        function keepSlidesPosition(){
26243            $(SLIDE_ACTIVE_SEL).each(function(){
26244                silentLandscapeScroll($(this), 'internal');
26245            });
26246        }
26247
26248        var previousDestTop = 0;
26249        /**
26250        * Returns the destination Y position based on the scrolling direction and
26251        * the height of the section.
26252        */
26253        function getDestinationPosition(element){
26254            var elemPosition = element.position();
26255
26256            //top of the desination will be at the top of the viewport
26257            var position = elemPosition.top;
26258            var isScrollingDown =  elemPosition.top > previousDestTop;
26259            var sectionBottom = position - windowsHeight + element.outerHeight();
26260            var bigSectionsDestination = options.bigSectionsDestination;
26261
26262            //Uncode addition
26263            var containerH = container.outerHeight();
26264            var containerPosition = container.offset();
26265
26266            //########### Commented by Uncode - START ###########
26267            //is the destination element bigger than the viewport?
26268            // if(element.outerHeight() > windowsHeight){
26269            //     //scrolling up?
26270            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
26271            //         position = sectionBottom;
26272            //     }
26273            // }
26274
26275            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
26276            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
26277            //     //The bottom of the destination will be at the bottom of the viewport
26278            //     position = sectionBottom;
26279            // }
26280            //########### Commented by Uncode - END ###########
26281
26282            //Uncode addition
26283            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
26284                position += 18;
26285            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
26286                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
26287            }
26288
26289            /*
26290            Keeping record of the last scrolled position to determine the scrolling direction.
26291            No conventional methods can be used as the scroll bar might not be present
26292            AND the section might not be active if it is auto-height and didnt reach the middle
26293            of the viewport.
26294            */
26295            previousDestTop = position;
26296            return position;
26297        }
26298
26299        /**
26300        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
26301        */
26302        function scrollPage(element, callback, isMovementUp){
26303            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
26304
26305            var dtop = getDestinationPosition(element);
26306            var slideAnchorLink;
26307            var slideIndex;
26308
26309            //local variables
26310            var v = {
26311                element: element,
26312                callback: callback,
26313                isMovementUp: isMovementUp,
26314                dtop: dtop,
26315                yMovement: getYmovement(element),
26316                anchorLink: element.data('anchor'),
26317                sectionIndex: element.index(SECTION_SEL),
26318                activeSlide: element.find(SLIDE_ACTIVE_SEL),
26319                activeSection: $(SECTION_ACTIVE_SEL),
26320                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
26321
26322                //caching the value of isResizing at the momment the function is called
26323                //because it will be checked later inside a setTimeout and the value might change
26324                localIsResizing: isResizing
26325            };
26326
26327            //quiting when destination scroll is the same as the current one
26328            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
26329
26330            if(v.activeSlide.length){
26331                slideAnchorLink = v.activeSlide.data('anchor');
26332                slideIndex = v.activeSlide.index();
26333            }
26334
26335            // If continuousVertical && we need to wrap around
26336            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
26337                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
26338                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
26339
26340                v = createInfiniteSections(v);
26341            }
26342
26343            //callback (onLeave) if the site is not just resizing and readjusting the slides
26344            if($.isFunction(options.onLeave) && !v.localIsResizing){
26345                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
26346                    return;
26347                }
26348            }
26349
26350            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
26351            if(!v.localIsResizing){
26352                stopMedia(v.activeSection);
26353            }
26354
26355            options.scrollOverflowHandler.beforeLeave();
26356            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
26357            lazyLoad(element);
26358            options.scrollOverflowHandler.onLeave();
26359
26360
26361            //preventing from activating the MouseWheelHandler event
26362            //more than once if the page is scrolling
26363            canScroll = false;
26364
26365            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
26366
26367            performMovement(v);
26368
26369            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
26370            lastScrolledDestiny = v.anchorLink;
26371
26372            //avoid firing it twice (as it does also on scroll)
26373            activateMenuAndNav(v.anchorLink, v.sectionIndex);
26374        }
26375
26376        /**
26377        * Performs the vertical movement (by CSS3 or by jQuery)
26378        */
26379        function performMovement(v){
26380            // using CSS3 translate functionality
26381            if (options.css3 && options.autoScrolling && !options.scrollBar) {
26382
26383                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
26384                // that's why we round it to 0.
26385                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
26386                transformContainer(translate3d, true);
26387
26388                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
26389                //scrollingSpeed to change in case of using silentMoveTo();
26390                if(options.scrollingSpeed){
26391                    clearTimeout(afterSectionLoadsId);
26392                    afterSectionLoadsId = setTimeout(function () {
26393                        afterSectionLoads(v);
26394                    }, options.scrollingSpeed);
26395                }else{
26396                    afterSectionLoads(v);
26397                }
26398            }
26399
26400            // using jQuery animate
26401            else{
26402                var scrollSettings = getScrollSettings(v);
26403
26404                $(scrollSettings.element).animate(
26405                    scrollSettings.options,
26406                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
26407                    if(options.scrollBar){
26408
26409                        /* Hack!
26410                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
26411                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
26412
26413                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
26414                        */
26415                        setTimeout(function(){
26416                            afterSectionLoads(v);
26417                        },30);
26418                    }else{
26419                        afterSectionLoads(v);
26420                    }
26421                });
26422            }
26423        }
26424
26425        /**
26426        * Gets the scrolling settings depending on the plugin autoScrolling option
26427        */
26428        function getScrollSettings(v){
26429            var scroll = {};
26430
26431            if(options.autoScrolling && !options.scrollBar){
26432                scroll.options = { 'top': -v.dtop};
26433                scroll.element = WRAPPER_SEL;
26434            }else{
26435                scroll.options = { 'scrollTop': v.dtop};
26436                scroll.element = 'html, body';
26437            }
26438
26439            return scroll;
26440        }
26441
26442        /**
26443        * Adds sections before or after the current one to create the infinite effect.
26444        */
26445        function createInfiniteSections(v){
26446            // Scrolling down
26447            if (!v.isMovementUp) {
26448                // Move all previous sections to after the active section
26449                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
26450            }
26451            else { // Scrolling up
26452                // Move all next sections to before the active section
26453                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
26454            }
26455
26456            // Maintain the displayed position (now that we changed the element order)
26457            silentScroll($(SECTION_ACTIVE_SEL).position().top);
26458
26459            // Maintain the active slides visible in the viewport
26460            keepSlidesPosition();
26461
26462            // save for later the elements that still need to be reordered
26463            v.wrapAroundElements = v.activeSection;
26464
26465            // Recalculate animation variables
26466            v.dtop = v.element.position().top;
26467            v.yMovement = getYmovement(v.element);
26468
26469            return v;
26470        }
26471
26472        /**
26473        * Fix section order after continuousVertical changes have been animated
26474        */
26475        function continuousVerticalFixSectionOrder (v) {
26476            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
26477            // finish moving the elements around so the direct navigation will function more simply
26478            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
26479                return;
26480            }
26481
26482            if (v.isMovementUp) {
26483                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
26484            }
26485            else {
26486                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
26487            }
26488
26489            silentScroll($(SECTION_ACTIVE_SEL).position().top);
26490
26491            // Maintain the active slides visible in the viewport
26492            keepSlidesPosition();
26493        }
26494
26495
26496        /**
26497        * Actions to do once the section is loaded.
26498        */
26499        function afterSectionLoads (v){
26500            continuousVerticalFixSectionOrder(v);
26501
26502            //callback (afterLoad) if the site is not just resizing and readjusting the slides
26503            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
26504            options.scrollOverflowHandler.afterLoad();
26505
26506            if(!v.localIsResizing){
26507                playMedia(v.element);
26508            }
26509
26510            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
26511
26512            canScroll = true;
26513
26514            $.isFunction(v.callback) && v.callback.call(this);
26515        }
26516
26517        /**
26518        * Sets the value for the given attribute from the `data-` attribute with the same suffix
26519        * ie: data-srcset ==> srcset  |  data-src ==> src
26520        */
26521        function setSrc(element, attribute){
26522            element
26523                .attr(attribute, element.data(attribute))
26524                .removeAttr('data-' + attribute);
26525        }
26526
26527        /**
26528        * Lazy loads image, video and audio elements.
26529        */
26530        function lazyLoad(destiny){
26531            if (!options.lazyLoading){
26532                return;
26533            }
26534
26535            var panel = getSlideOrSection(destiny);
26536            var element;
26537
26538            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
26539                element = $(this);
26540
26541                $.each(['src', 'srcset'], function(index, type){
26542                    var attribute = element.attr('data-' + type);
26543                    if(typeof attribute !== 'undefined' && attribute){
26544                        setSrc(element, type);
26545                    }
26546                });
26547
26548                if(element.is('source')){
26549                    element.closest('video').get(0).load();
26550                }
26551            });
26552        }
26553
26554        /**
26555        * Plays video and audio elements.
26556        */
26557        function playMedia(destiny){
26558            var panel = getSlideOrSection(destiny);
26559
26560            //playing HTML5 media elements
26561            panel.find('video, audio').each(function(){
26562                var element = $(this).get(0);
26563
26564                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
26565                    element.play();
26566                }
26567            });
26568
26569            //youtube videos
26570            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
26571                var element = $(this).get(0);
26572
26573                if ( element.hasAttribute('data-autoplay') ){
26574                    playYoutube(element);
26575                }
26576
26577                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
26578                element.onload = function() {
26579                    if ( element.hasAttribute('data-autoplay') ){
26580                        playYoutube(element);
26581                    }
26582                };
26583            });
26584        }
26585
26586        /**
26587        * Plays a youtube video
26588        */
26589        function playYoutube(element){
26590            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
26591        }
26592
26593        /**
26594        * Stops video and audio elements.
26595        */
26596        function stopMedia(destiny){
26597            var panel = getSlideOrSection(destiny);
26598
26599            //stopping HTML5 media elements
26600            panel.find('video, audio').each(function(){
26601                var element = $(this).get(0);
26602
26603                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
26604                    element.pause();
26605                }
26606            });
26607
26608            //youtube videos
26609            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
26610                var element = $(this).get(0);
26611
26612                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
26613                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
26614                }
26615            });
26616        }
26617
26618        /**
26619        * Gets the active slide (or section) for the given section
26620        */
26621        function getSlideOrSection(destiny){
26622            var slide = destiny.find(SLIDE_ACTIVE_SEL);
26623            if( slide.length ) {
26624                destiny = $(slide);
26625            }
26626
26627            return destiny;
26628        }
26629
26630        /**
26631        * Scrolls to the anchor in the URL when loading the site
26632        */
26633        function scrollToAnchor(){
26634            //getting the anchor link in the URL and deleting the `#`
26635            var value =  window.location.hash.replace('#', '').split('/');
26636            var sectionAnchor = decodeURIComponent(value[0]);
26637            var slideAnchor = decodeURIComponent(value[1]);
26638
26639            if(sectionAnchor){  //if theres any #
26640                if(options.animateAnchor){
26641                    scrollPageAndSlide(sectionAnchor, slideAnchor);
26642                }else{
26643                    silentMoveTo(sectionAnchor, slideAnchor);
26644                }
26645            }
26646        }
26647
26648        /**
26649        * Detecting any change on the URL to scroll to the given anchor link
26650        * (a way to detect back history button as we play with the hashes on the URL)
26651        */
26652        function hashChangeHandler(){
26653            if(!isScrolling && !options.lockAnchors){
26654                var value =  window.location.hash.replace('#', '').split('/');
26655                var sectionAnchor = decodeURIComponent(value[0]);
26656                var slideAnchor = decodeURIComponent(value[1]);
26657
26658                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
26659                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
26660                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
26661
26662
26663                if(sectionAnchor.length){
26664                    /*in order to call scrollpage() only once for each destination at a time
26665                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
26666                    event is fired on every scroll too.*/
26667                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
26668                        scrollPageAndSlide(sectionAnchor, slideAnchor);
26669                    }
26670                }
26671            }
26672        }
26673
26674        //Sliding with arrow keys, both, vertical and horizontal
26675        function keydownHandler(e) {
26676
26677            clearTimeout(keydownId);
26678
26679            var activeElement = $(':focus');
26680
26681            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
26682                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
26683                options.keyboardScrolling && options.autoScrolling){
26684                var keyCode = e.which;
26685
26686                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
26687                var keyControls = [40, 38, 32, 33, 34];
26688                if($.inArray(keyCode, keyControls) > -1){
26689                    e.preventDefault();
26690                }
26691
26692                controlPressed = e.ctrlKey;
26693
26694                keydownId = setTimeout(function(){
26695                    onkeydown(e);
26696                },150);
26697            }
26698        }
26699
26700        function tooltipTextHandler(){
26701            $(this).prev().trigger('click');
26702        }
26703
26704        //to prevent scrolling while zooming
26705        function keyUpHandler(e){
26706            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
26707                controlPressed = e.ctrlKey;
26708            }
26709        }
26710
26711        //binding the mousemove when the mouse's middle button is released
26712        function mouseDownHandler(e){
26713            //middle button
26714            if (e.which == 2){
26715                oldPageY = e.pageY;
26716                container.on('mousemove', mouseMoveHandler);
26717            }
26718        }
26719
26720        //unbinding the mousemove when the mouse's middle button is released
26721        function mouseUpHandler(e){
26722            //middle button
26723            if (e.which == 2){
26724                container.off('mousemove');
26725            }
26726        }
26727
26728        //Scrolling horizontally when clicking on the slider controls.
26729        function slideArrowHandler(){
26730            var section = $(this).closest(SECTION_SEL);
26731
26732            if ($(this).hasClass(SLIDES_PREV)) {
26733                if(isScrollAllowed.m.left){
26734                    moveSlideLeft(section);
26735                }
26736            } else {
26737                if(isScrollAllowed.m.right){
26738                    moveSlideRight(section);
26739                }
26740            }
26741        }
26742
26743        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
26744        function blurHandler(){
26745            isWindowFocused = false;
26746            controlPressed = false;
26747        }
26748
26749        //Scrolls to the section when clicking the navigation bullet
26750        function sectionBulletHandler(e){
26751            e.preventDefault();
26752            var index = $(this).parent().index();
26753            scrollPage($(SECTION_SEL).eq(index));
26754        }
26755
26756        //Scrolls the slider to the given slide destination for the given section
26757        function slideBulletHandler(e){
26758            e.preventDefault();
26759            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
26760            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
26761
26762            landscapeScroll(slides, destiny);
26763        }
26764
26765        /**
26766        * Keydown event
26767        */
26768        function onkeydown(e){
26769            var shiftPressed = e.shiftKey;
26770
26771            //do nothing if we can not scroll or we are not using horizotnal key arrows.
26772            if(!canScroll && [37,39].indexOf(e.which) < 0){
26773                return;
26774            }
26775
26776            switch (e.which) {
26777                //up
26778                case 38:
26779                case 33:
26780                    if(isScrollAllowed.k.up){
26781                        moveSectionUp();
26782                    }
26783                    break;
26784
26785                //down
26786                case 32: //spacebar
26787                    if(shiftPressed && isScrollAllowed.k.up){
26788                        moveSectionUp();
26789                        break;
26790                    }
26791                /* falls through */
26792                case 40:
26793                case 34:
26794                    if(isScrollAllowed.k.down){
26795                        moveSectionDown();
26796                    }
26797                    break;
26798
26799                //Home
26800                case 36:
26801                    if(isScrollAllowed.k.up){
26802                        moveTo(1);
26803                    }
26804                    break;
26805
26806                //End
26807                case 35:
26808                     if(isScrollAllowed.k.down){
26809                        moveTo( $(SECTION_SEL).length );
26810                    }
26811                    break;
26812
26813                //left
26814                case 37:
26815                    if(isScrollAllowed.k.left){
26816                        moveSlideLeft();
26817                    }
26818                    break;
26819
26820                //right
26821                case 39:
26822                    if(isScrollAllowed.k.right){
26823                        moveSlideRight();
26824                    }
26825                    break;
26826
26827                default:
26828                    return; // exit this handler for other keys
26829            }
26830        }
26831
26832        /**
26833        * Detecting the direction of the mouse movement.
26834        * Used only for the middle button of the mouse.
26835        */
26836        var oldPageY = 0;
26837        function mouseMoveHandler(e){
26838            if(canScroll){
26839                // moving up
26840                if (e.pageY < oldPageY && isScrollAllowed.m.up){
26841                    moveSectionUp();
26842                }
26843
26844                // moving down
26845                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
26846                    moveSectionDown();
26847                }
26848            }
26849            oldPageY = e.pageY;
26850        }
26851
26852        /**
26853        * Scrolls horizontal sliders.
26854        */
26855        function landscapeScroll(slides, destiny, direction){
26856            var section = slides.closest(SECTION_SEL);
26857            var v = {
26858                slides: slides,
26859                destiny: destiny,
26860                direction: direction,
26861                destinyPos: destiny.position(),
26862                slideIndex: destiny.index(),
26863                section: section,
26864                sectionIndex: section.index(SECTION_SEL),
26865                anchorLink: section.data('anchor'),
26866                slidesNav: section.find(SLIDES_NAV_SEL),
26867                slideAnchor:  getAnchor(destiny),
26868                prevSlide: section.find(SLIDE_ACTIVE_SEL),
26869                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
26870
26871                //caching the value of isResizing at the momment the function is called
26872                //because it will be checked later inside a setTimeout and the value might change
26873                localIsResizing: isResizing
26874            };
26875            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
26876            v.direction = v.direction ? v.direction : v.xMovement;
26877
26878            //important!! Only do it when not resizing
26879            if(!v.localIsResizing){
26880                //preventing from scrolling to the next/prev section when using scrollHorizontally
26881                canScroll = false;
26882            }
26883
26884            if(options.onSlideLeave){
26885
26886                //if the site is not just resizing and readjusting the slides
26887                if(!v.localIsResizing && v.xMovement!=='none'){
26888                    if($.isFunction( options.onSlideLeave )){
26889                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
26890                            slideMoving = false;
26891                            return;
26892                        }
26893                    }
26894                }
26895            }
26896
26897            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
26898
26899            if(!v.localIsResizing){
26900                stopMedia(v.prevSlide);
26901                lazyLoad(destiny);
26902            }
26903
26904            if(!options.loopHorizontal && options.controlArrows){
26905                //hidding it for the fist slide, showing for the rest
26906                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
26907
26908                //hidding it for the last slide, showing for the rest
26909                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
26910            }
26911
26912            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
26913            if(section.hasClass(ACTIVE) && !v.localIsResizing){
26914                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
26915            }
26916
26917            performHorizontalMove(slides, v, true);
26918        }
26919
26920
26921        function afterSlideLoads(v){
26922            activeSlidesNavigation(v.slidesNav, v.slideIndex);
26923
26924            //if the site is not just resizing and readjusting the slides
26925            if(!v.localIsResizing){
26926                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
26927
26928                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
26929                //and to prevent double scroll right after a windows resize
26930                canScroll = true;
26931
26932                playMedia(v.destiny);
26933            }
26934
26935            //letting them slide again
26936            slideMoving = false;
26937        }
26938
26939        /**
26940        * Performs the horizontal movement. (CSS3 or jQuery)
26941        *
26942        * @param fireCallback {Bool} - determines whether or not to fire the callback
26943        */
26944        function performHorizontalMove(slides, v, fireCallback){
26945            var destinyPos = v.destinyPos;
26946
26947            if(options.css3){
26948                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
26949
26950                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
26951
26952                afterSlideLoadsId = setTimeout(function(){
26953                    fireCallback && afterSlideLoads(v);
26954                }, options.scrollingSpeed, options.easing);
26955            }else{
26956                slides.animate({
26957                    scrollLeft : Math.round(destinyPos.left)
26958                }, options.scrollingSpeed, options.easing, function() {
26959
26960                    fireCallback && afterSlideLoads(v);
26961                });
26962            }
26963        }
26964
26965        /**
26966        * Sets the state for the horizontal bullet navigations.
26967        */
26968        function activeSlidesNavigation(slidesNav, slideIndex){
26969            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
26970            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
26971        }
26972
26973        var previousHeight = windowsHeight;
26974
26975        //when resizing the site, we adjust the heights of the sections, slimScroll...
26976        function resizeHandler(){
26977            //checking if it needs to get responsive
26978            responsive();
26979
26980            // rebuild immediately on touch devices
26981            if (isTouchDevice) {
26982                var activeElement = $(document.activeElement);
26983
26984                //if the keyboard is NOT visible
26985                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
26986                    var currentHeight = $window.height();
26987
26988                    //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)
26989                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
26990                        reBuild(true);
26991                        previousHeight = currentHeight;
26992                    }
26993                }
26994            }else{
26995                //in order to call the functions only when the resize is finished
26996                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
26997                clearTimeout(resizeId);
26998
26999                resizeId = setTimeout(function(){
27000                    reBuild(true);
27001                }, 350);
27002            }
27003        }
27004
27005        /**
27006        * Checks if the site needs to get responsive and disables autoScrolling if so.
27007        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
27008        */
27009        function responsive(){
27010            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
27011            var heightLimit = options.responsiveHeight;
27012
27013            //only calculating what we need. Remember its called on the resize event.
27014            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
27015            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
27016
27017            if(widthLimit && heightLimit){
27018                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
27019            }
27020            else if(widthLimit){
27021                setResponsive(isBreakingPointWidth);
27022            }
27023            else if(heightLimit){
27024                setResponsive(isBreakingPointHeight);
27025            }
27026        }
27027
27028        /**
27029        * Adds transition animations for the given element
27030        */
27031        function addAnimation(container, element){
27032            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
27033
27034            container.removeClass(NO_TRANSITION);
27035            return container.css({
27036                '-webkit-transition': transition,
27037                'transition': transition
27038            });
27039        }
27040
27041        /**
27042        * Remove transition animations for the given element
27043        */
27044        function removeAnimation(element){
27045            return element.addClass(NO_TRANSITION);
27046        }
27047
27048        /**
27049        * Activating the vertical navigation bullets according to the given slide name.
27050        */
27051        function activateNavDots(name, sectionIndex){
27052            if(options.navigation){
27053                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
27054                if(name){
27055                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
27056                }else{
27057                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
27058                }
27059            }
27060        }
27061
27062        /**
27063        * Activating the website main menu elements according to the given slide name.
27064        */
27065        function activateMenuElement(name){
27066            if(options.menu){
27067                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
27068                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
27069            }
27070        }
27071
27072        /**
27073        * Sets to active the current menu and vertical nav items.
27074        */
27075        function activateMenuAndNav(anchor, index){
27076            activateMenuElement(anchor);
27077            activateNavDots(anchor, index);
27078        }
27079
27080        /**
27081        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
27082        * from the current section.
27083        */
27084        function getYmovement(destiny){
27085            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
27086            var toIndex = destiny.index(SECTION_SEL);
27087            if( fromIndex == toIndex){
27088                return 'none';
27089            }
27090            if(fromIndex > toIndex){
27091                return 'up';
27092            }
27093            return 'down';
27094        }
27095
27096        /**
27097        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
27098        * from the current slide.
27099        */
27100        function getXmovement(fromIndex, toIndex){
27101            if( fromIndex == toIndex){
27102                return 'none';
27103            }
27104            if(fromIndex > toIndex){
27105                return 'left';
27106            }
27107            return 'right';
27108        }
27109
27110        /**
27111        * Checks if the element needs scrollbar and if the user wants to apply it.
27112        * If so it creates it.
27113        *
27114        * @param {Object} element   jQuery object of the section or slide
27115        */
27116        function createScrollBar(element){
27117            //User doesn't want scrollbar here? Sayonara baby!
27118            if(element.hasClass('fp-noscroll')) return;
27119
27120            //needed to make `scrollHeight` work under Opera 12
27121            element.css('overflow', 'hidden');
27122
27123            var scrollOverflowHandler = options.scrollOverflowHandler;
27124            var wrap = scrollOverflowHandler.wrapContent();
27125            //in case element is a slide
27126            var section = element.closest(SECTION_SEL);
27127            var scrollable = scrollOverflowHandler.scrollable(element);
27128            var contentHeight;
27129
27130            //if there was scroll, the contentHeight will be the one in the scrollable section
27131            if(scrollable.length){
27132                contentHeight = scrollOverflowHandler.scrollHeight(element);
27133            }else{
27134                contentHeight = element.get(0).scrollHeight;
27135                if(options.verticalCentered){
27136                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
27137                }
27138            }
27139
27140            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
27141
27142            //needs scroll?
27143            if ( contentHeight > scrollHeight) {
27144                //did we already have an scrollbar ? Updating it
27145                if(scrollable.length){
27146                    scrollOverflowHandler.update(element, scrollHeight);
27147                }
27148                //creating the scrolling
27149                else{
27150                    if(options.verticalCentered){
27151                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
27152                    }else{
27153                        element.wrapInner(wrap);
27154                    }
27155                    scrollOverflowHandler.create(element, scrollHeight);
27156                }
27157            }
27158            //removing the scrolling when it is not necessary anymore
27159            else{
27160                scrollOverflowHandler.remove(element);
27161            }
27162
27163            //undo
27164            element.css('overflow', '');
27165        }
27166
27167        function addTableClass(element){
27168            //In case we are styling for the 2nd time as in with reponsiveSlides
27169            if(!element.hasClass(TABLE)){
27170                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
27171            }
27172        }
27173
27174        function getTableHeight(element){
27175            var sectionHeight = windowsHeight;
27176
27177            if(options.paddingTop || options.paddingBottom){
27178                var section = element;
27179                if(!section.hasClass(SECTION)){
27180                    section = element.closest(SECTION_SEL);
27181                }
27182
27183                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
27184                sectionHeight = (windowsHeight - paddings);
27185            }
27186
27187            return sectionHeight;
27188        }
27189
27190        /**
27191        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
27192        */
27193        function transformContainer(translate3d, animated){
27194            if(animated){
27195                addAnimation(container);
27196            }else{
27197                removeAnimation(container);
27198            }
27199
27200            container.css(getTransforms(translate3d));
27201
27202            //syncronously removing the class after the animation has been applied.
27203            setTimeout(function(){
27204                container.removeClass(NO_TRANSITION);
27205            },10);
27206        }
27207
27208        /**
27209        * Gets a section by its anchor / index
27210        */
27211        function getSectionByAnchor(sectionAnchor){
27212            if(!sectionAnchor) return [];
27213
27214            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
27215            if(!section.length){
27216                section = $(SECTION_SEL).eq( sectionAnchor -1);
27217            }
27218
27219            return section;
27220        }
27221
27222        /**
27223        * Gets a slide inside a given section by its anchor / index
27224        */
27225        function getSlideByAnchor(slideAnchor, section){
27226            var slides = section.find(SLIDES_WRAPPER_SEL);
27227            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
27228
27229            if(!slide.length){
27230                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
27231            }
27232
27233            return slide;
27234        }
27235
27236        /**
27237        * Scrolls to the given section and slide anchors
27238        */
27239        function scrollPageAndSlide(destiny, slide){
27240            var section = getSectionByAnchor(destiny);
27241
27242            //do nothing if there's no section with the given anchor name
27243            if(!section.length) return;
27244
27245            //default slide
27246            if (typeof slide === 'undefined') {
27247                slide = 0;
27248            }
27249
27250            //we need to scroll to the section and then to the slide
27251            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
27252                scrollPage(section, function(){
27253                    scrollSlider(section, slide);
27254                });
27255            }
27256            //if we were already in the section
27257            else{
27258                scrollSlider(section, slide);
27259            }
27260        }
27261
27262        /**
27263        * Scrolls the slider to the given slide destination for the given section
27264        */
27265        function scrollSlider(section, slideAnchor){
27266            if(typeof slideAnchor !== 'undefined'){
27267                var slides = section.find(SLIDES_WRAPPER_SEL);
27268                var destiny =  getSlideByAnchor(slideAnchor, section);
27269
27270                if(destiny.length){
27271                    landscapeScroll(slides, destiny);
27272                }
27273            }
27274        }
27275
27276        /**
27277        * Creates a landscape navigation bar with dots for horizontal sliders.
27278        */
27279        function addSlidesNavigation(section, numSlides){
27280            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
27281            var nav = section.find(SLIDES_NAV_SEL);
27282
27283            //top or bottom
27284            nav.addClass(options.slidesNavPosition);
27285
27286            for(var i=0; i< numSlides; i++){
27287                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
27288            }
27289
27290            //centering it
27291            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
27292
27293            nav.find('li').first().find('a').addClass(ACTIVE);
27294        }
27295
27296
27297        /**
27298        * Sets the state of the website depending on the active section/slide.
27299        * It changes the URL hash when needed and updates the body class.
27300        */
27301        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
27302            var sectionHash = '';
27303
27304            if(options.anchors.length && !options.lockAnchors){
27305
27306                //isn't it the first slide?
27307                if(slideIndex){
27308                    if(typeof anchorLink !== 'undefined'){
27309                        sectionHash = anchorLink;
27310                    }
27311
27312                    //slide without anchor link? We take the index instead.
27313                    if(typeof slideAnchor === 'undefined'){
27314                        slideAnchor = slideIndex;
27315                    }
27316
27317                    lastScrolledSlide = slideAnchor;
27318                    setUrlHash(sectionHash + '/' + slideAnchor);
27319
27320                //first slide won't have slide anchor, just the section one
27321                }else if(typeof slideIndex !== 'undefined'){
27322                    lastScrolledSlide = slideAnchor;
27323                    setUrlHash(anchorLink);
27324                }
27325
27326                //section without slides
27327                else{
27328                    setUrlHash(anchorLink);
27329                }
27330            }
27331
27332            setBodyClass();
27333        }
27334
27335        /**
27336        * Sets the URL hash.
27337        */
27338        function setUrlHash(url){
27339            //Uncode addition
27340            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
27341                return false;
27342
27343            if(options.recordHistory){
27344                location.hash = url;
27345            }else{
27346                //Uncode addition
27347                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
27348                // if(isTouchDevice || isTouch){
27349                //     window.history.replaceState(undefined, undefined, '#' + url);
27350                // }else{
27351                //     var baseUrl = window.location.href.split('#')[0];
27352                //     window.location.replace( baseUrl + '#' + url );
27353                // }
27354                return false;
27355            }
27356        }
27357
27358        /**
27359        * Gets the anchor for the given slide / section. Its index will be used if there's none.
27360        */
27361        function getAnchor(element){
27362            var anchor = element.data('anchor');
27363            var index = element.index();
27364
27365            //Slide without anchor link? We take the index instead.
27366            if(typeof anchor === 'undefined'){
27367                anchor = index;
27368            }
27369
27370            return anchor;
27371        }
27372
27373        /**
27374        * Sets a class for the body of the page depending on the active section / slide
27375        */
27376        function setBodyClass(){
27377            var section = $(SECTION_ACTIVE_SEL);
27378            var slide = section.find(SLIDE_ACTIVE_SEL);
27379
27380            var sectionAnchor = getAnchor(section);
27381            var slideAnchor = getAnchor(slide);
27382
27383            var text = String(sectionAnchor);
27384
27385            if(slide.length){
27386                text = text + '-' + slideAnchor;
27387            }
27388
27389            //changing slash for dash to make it a valid CSS style
27390            text = text.replace('/', '-').replace('#','');
27391
27392            //removing previous anchor classes
27393            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
27394            $body[0].className = $body[0].className.replace(classRe, '');
27395
27396            //adding the current anchor
27397            $body.addClass(VIEWING_PREFIX + '-' + text);
27398        }
27399
27400        /**
27401        * Checks for translate3d support
27402        * @return boolean
27403        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
27404        */
27405        function support3d() {
27406            var el = document.createElement('p'),
27407                has3d,
27408                transforms = {
27409                    'webkitTransform':'-webkit-transform',
27410                    'OTransform':'-o-transform',
27411                    'msTransform':'-ms-transform',
27412                    'MozTransform':'-moz-transform',
27413                    'transform':'transform'
27414                };
27415
27416            // Add it to the body to get the computed style.
27417            document.body.insertBefore(el, null);
27418
27419            for (var t in transforms) {
27420                if (el.style[t] !== undefined) {
27421                    el.style[t] = 'translate3d(1px,1px,1px)';
27422                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
27423                }
27424            }
27425
27426            document.body.removeChild(el);
27427
27428            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
27429        }
27430
27431        /**
27432        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
27433        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
27434        */
27435        function removeMouseWheelHandler(){
27436            if (document.addEventListener) {
27437                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
27438                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
27439                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
27440            } else {
27441                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
27442            }
27443        }
27444
27445        /**
27446        * Adds the auto scrolling action for the mouse wheel and trackpad.
27447        * After this function is called, the mousewheel and trackpad movements will scroll through sections
27448        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
27449        */
27450        function addMouseWheelHandler(){
27451            var prefix = '';
27452            var _addEventListener;
27453
27454            if (window.addEventListener){
27455                _addEventListener = "addEventListener";
27456            }else{
27457                _addEventListener = "attachEvent";
27458                prefix = 'on';
27459            }
27460
27461             // detect available wheel event
27462            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
27463                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
27464                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
27465            var passiveEvent = g_supportsPassive ? {passive: false }
27465: false;
27466
27467
27468            if(support == 'DOMMouseScroll'){
27469                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent);
27470            }
27471
27472            //handle MozMousePixelScroll in older Firefox
27473            else{
27474                document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent);
27475            }
27476        }
27477
27478        /**
27479        * Binding the mousemove when the mouse's middle button is pressed
27480        */
27481        function addMiddleWheelHandler(){
27482            container
27483                .on('mousedown', mouseDownHandler)
27484                .on('mouseup', mouseUpHandler);
27485        }
27486
27487        /**
27488        * Unbinding the mousemove when the mouse's middle button is released
27489        */
27490        function removeMiddleWheelHandler(){
27491            container
27492                .off('mousedown', mouseDownHandler)
27493                .off('mouseup', mouseUpHandler);
27494        }
27495
27496        /**
27497        * Adds the possibility to auto scroll through sections on touch devices.
27498        */
27499        function addTouchHandler(){
27500            if(isTouchDevice || isTouch){
27501                if(options.autoScrolling){
27502                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
27503                }
27504
27505                $(WRAPPER_SEL)
27506                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
27507                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
27508            }
27509        }
27510
27511        /**
27512        * Removes the auto scrolling for touch devices.
27513        */
27514        function removeTouchHandler(){
27515            if(isTouchDevice || isTouch){
27516                $(WRAPPER_SEL)
27517                    .off(events.touchstart)
27518                    .off(events.touchmove);
27519            }
27520        }
27521
27522        /*
27523        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
27524        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
27525        */
27526        function getMSPointer(){
27527            var pointer;
27528
27529            //IE >= 11 & rest of browsers
27530            if(window.PointerEvent){
27531                pointer = { down: 'pointerdown', move: 'pointermove'};
27532            }
27533
27534            //IE < 11
27535            else{
27536                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
27537            }
27538
27539            return pointer;
27540        }
27541
27542        /**
27543        * Gets the pageX and pageY properties depending on the browser.
27544        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
27545        */
27546        function getEventsPage(e){
27547            var events = [];
27548
27549            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
27550            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
27551
27552            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
27553            if(isTouch && isReallyTouch(e) && options.scrollBar){
27554                events.y = e.touches[0].pageY;
27555                events.x = e.touches[0].pageX;
27556            }
27557
27558            return events;
27559        }
27560
27561        /**
27562        * Slides silently (with no animation) the active slider to the given slide.
27563        * @param noCallback {bool} true or defined -> no callbacks
27564        */
27565        function silentLandscapeScroll(activeSlide, noCallbacks){
27566            setScrollingSpeed (0, 'internal');
27567
27568            if(typeof noCallbacks !== 'undefined'){
27569                //preventing firing callbacks afterSlideLoad etc.
27570                isResizing = true;
27571            }
27572
27573            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
27574
27575            if(typeof noCallbacks !== 'undefined'){
27576                isResizing = false;
27577            }
27578
27579            setScrollingSpeed(originals.scrollingSpeed, 'internal');
27580        }
27581
27582        /**
27583        * Scrolls silently (with no animation) the page to the given Y position.
27584        */
27585        function silentScroll(top){
27586            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
27587            // that's why we round it to 0.
27588            var roundedTop = Math.round(top);
27589
27590            if (options.css3 && options.autoScrolling && !options.scrollBar){
27591                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
27592                transformContainer(translate3d, false);
27593            }
27594            else if(options.autoScrolling && !options.scrollBar){
27595                container.css('top', -roundedTop);
27596            }
27597            else{
27598                $htmlBody.scrollTop(roundedTop);
27599            }
27600        }
27601
27602        /**
27603        * Returns the cross-browser transform string.
27604        */
27605        function getTransforms(translate3d){
27606            return {
27607                '-webkit-transform': translate3d,
27608                '-moz-transform': translate3d,
27609                '-ms-transform':translate3d,
27610                'transform': translate3d
27611            };
27612        }
27613
27614        /**
27615        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
27616        * @type  m (mouse) or k (keyboard)
27617        */
27618        function setIsScrollAllowed(value, direction, type){
27619            switch (direction){
27620                case 'up': isScrollAllowed[type].up = value; break;
27621                case 'down': isScrollAllowed[type].down = value; break;
27622                case 'left': isScrollAllowed[type].left = value; break;
27623                case 'right': isScrollAllowed[type].right = value; break;
27624                case 'all':
27625                    if(type == 'm'){
27626                        setAllowScrolling(value);
27627                    }else{
27628                        setKeyboardScrolling(value);
27629                    }
27630            }
27631        }
27632
27633        /*
27634        * Destroys fullpage.js plugin events and optinally its html markup and styles
27635        */
27636        function destroy(all){
27637            setAutoScrolling(false, 'internal');
27638            setAllowScrolling(false);
27639            setKeyboardScrolling(false);
27640            container.addClass(DESTROYED);
27641
27642            clearTimeout(afterSlideLoadsId);
27643            clearTimeout(afterSectionLoadsId);
27644            clearTimeout(resizeId);
27645            clearTimeout(scrollId);
27646            clearTimeout(scrollId2);
27647
27648            $window
27649                .off('scroll', scrollHandler)
27650                .off('hashchange', hashChangeHandler)
27651                .off('resize', resizeHandler);
27652
27653            $document
27654                .off('click touchstart', SECTION_NAV_SEL + ' a')
27655                .off('mouseenter', SECTION_NAV_SEL + ' li')
27656                .off('mouseleave', SECTION_NAV_SEL + ' li')
27657                .off('click touchstart', SLIDES_NAV_LINK_SEL)
27658                .off('mouseover', options.normalScrollElements)
27659                .off('mouseout', options.normalScrollElements);
27660
27661            $(SECTION_SEL)
27662                .off('click touchstart', SLIDES_ARROW_SEL);
27663
27664            clearTimeout(afterSlideLoadsId);
27665            clearTimeout(afterSectionLoadsId);
27666
27667            //lets make a mess!
27668            if(all){
27669                destroyStructure();
27670            }
27671        }
27672
27673        /*
27674        * Removes inline styles added by fullpage.js
27675        */
27676        function destroyStructure(){
27677            //reseting the `top` or `translate` properties to 0
27678            silentScroll(0);
27679
27680            //loading all the lazy load content
27681            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
27682                setSrc($(this), 'src');
27683            });
27684
27685            container.find('img[data-srcset]').each(function(){
27686                setSrc($(this), 'srcset');
27687            });
27688
27689            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
27690
27691            //removing inline styles
27692            $(SECTION_SEL).css( {
27693                'height': '',
27694                'background-color' : '',
27695                'padding': ''
27696            });
27697
27698            $(SLIDE_SEL).css( {
27699                'width': ''
27700            });
27701
27702            container.css({
27703                'height': '',
27704                'position': '',
27705                '-ms-touch-action': '',
27706                'touch-action': ''
27707            });
27708
27709            $htmlBody.css({
27710                'overflow': '',
27711                'height': ''
27712            });
27713
27714            // remove .fp-enabled class
27715            $('html').removeClass(ENABLED);
27716
27717            // remove .fp-responsive class
27718            $body.removeClass(RESPONSIVE);
27719
27720            // remove all of the .fp-viewing- classes
27721            $.each($body.get(0).className.split(/\s+/), function (index, className) {
27722                if (className.indexOf(VIEWING_PREFIX) === 0) {
27723                    $body.removeClass(className);
27724                }
27725            });
27726
27727            //removing added classes
27728            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
27729                options.scrollOverflowHandler.remove($(this));
27730                $(this).removeClass(TABLE + ' ' + ACTIVE);
27731            });
27732
27733            removeAnimation(container);
27734
27735            //Unwrapping content
27736            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
27737                //unwrap not being use in case there's no child element inside and its just text
27738                $(this).replaceWith(this.childNodes);
27739            });
27740
27741            //removing the applied transition from the fullpage wrapper
27742            container.css({
27743                '-webkit-transition': 'none',
27744                'transition': 'none'
27745            });
27746
27747            //scrolling the page to the top with no animation
27748            $htmlBody.scrollTop(0);
27749
27750            //removing selectors
27751            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
27752            $.each(usedSelectors, function(index, value){
27753                $('.' + value).removeClass(value);
27754            });
27755        }
27756
27757        /*
27758        * Sets the state for a variable with multiple states (original, and temporal)
27759        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
27760        * This function is used to keep track of both states, the original and the temporal one.
27761        * If type is not 'internal', then we assume the user is globally changing the variable.
27762        */
27763        function setVariableState(variable, value, type){
27764            options[variable] = value;
27765            if(type !== 'internal'){
27766                originals[variable] = value;
27767            }
27768        }
27769
27770        /**
27771        * Displays warnings
27772        */
27773        function displayWarnings(){
27774            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
27775            //UNCODE.addition
27776            // if($('html').hasClass(ENABLED)){
27777            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
27778            //     return;
27779            // }
27780
27781            // Disable mutually exclusive settings
27782            //UNCODE.addition
27783            // if (options.continuousVertical &&
27784            //     (options.loopTop || options.loopBottom)) {
27785            //     options.continuousVertical = false;
27786            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
27787            // }
27788
27789            // if(options.scrollBar && options.scrollOverflow){
27790            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
27791            // }
27792
27793            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
27794            //     options.continuousVertical = false;
27795            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
27796            // }
27797
27798            //using extensions? Wrong file!
27799            $.each(extensions, function(index, extension){
27800                //is the option set to true?
27801                if(options[extension]){
27802                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
27803                }
27804            });
27805
27806            //anchors can not have the same value as any element ID or NAME
27807            $.each(options.anchors, function(index, name){
27808
27809                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
27810                var nameAttr = $document.find('[name]').filter(function() {
27811                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
27812                });
27813
27814                var idAttr = $document.find('[id]').filter(function() {
27815                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
27816                });
27817
27818                if(idAttr.length || nameAttr.length ){
27819                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
27820                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
27821                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
27822                }
27823            });
27824        }
27825
27826        /**
27827        * Shows a message in the console of the given type.
27828        */
27829        function showError(type, text){
27830            console && console[type] && console[type]('fullPage: ' + text);
27831        }
27832
27833    }; //end of $.fn.fullpage
27834
27835    if(typeof IScroll !== 'undefined'){
27836        /*
27837        * Turns iScroll `mousewheel` option off dynamically
27838        * https://github.com/cubiq/iscroll/issues/1036
27839        */
27840        IScroll.prototype.wheelOn = function () {
27841            this.wrapper.addEventListener('wheel', this);
27842            this.wrapper.addEventListener('mousewheel', this);
27843            this.wrapper.addEventListener('DOMMouseScroll', this);
27844        };
27845
27846        /*
27847        * Turns iScroll `mousewheel` option on dynamically
27848        * https://github.com/cubiq/iscroll/issues/1036
27849        */
27850        IScroll.prototype.wheelOff = function () {
27851            this.wrapper.removeEventListener('wheel', this);
27852            this.wrapper.removeEventListener('mousewheel', this);
27853            this.wrapper.removeEventListener('DOMMouseScroll', this);
27854        };
27855    }
27856
27857    /**
27858     * An object to handle overflow scrolling.
27859     * This uses jquery.slimScroll to accomplish overflow scrolling.
27860     * It is possible to pass in an alternate scrollOverflowHandler
27861     * to the fullpage.js option that implements the same functions
27862     * as this handler.
27863     *
27864     * @type {Object}
27865     */
27866    var iscrollHandler = {
27867        refreshId: null,
27868        iScrollInstances: [],
27869
27870        // Enables or disables the mouse wheel for the active section or all slides in it
27871        toggleWheel: function(value){
27872            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
27873            scrollable.each(function(){
27874                var iScrollInstance = $(this).data('iscrollInstance');
27875                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
27876                    if(value){
27877                        iScrollInstance.wheelOn();
27878                    }
27879                    else{
27880                        iScrollInstance.wheelOff();
27881                    }
27882                }
27883            });
27884        },
27885
27886        /**
27887        * Turns off iScroll for the destination section.
27888        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
27889        * scroll the destination section/slide before the sections animations ends.
27890        */
27891        onLeave: function(){
27892            iscrollHandler.toggleWheel(false);
27893        },
27894
27895        // Turns off iScroll for the leaving section
27896        beforeLeave: function(){
27897            iscrollHandler.onLeave()
27898        },
27899
27900        // Turns on iScroll on section load
27901        afterLoad: function(){
27902            iscrollHandler.toggleWheel(true);
27903        },
27904
27905        /**
27906         * Called when overflow scrolling is needed for a section.
27907         *
27908         * @param  {Object} element      jQuery object containing current section
27909         * @param  {Number} scrollHeight Current window height in pixels
27910         */
27911        create: function(element, scrollHeight) {
27912            var scrollable = element.find(SCROLLABLE_SEL);
27913
27914            scrollable.height(scrollHeight);
27915            scrollable.each(function() {
27916                var $this = $(this);
27917                var iScrollInstance = $this.data('iscrollInstance');
27918                if (iScrollInstance) {
27919                    $.each(iscrollHandler.iScrollInstances, function(){
27920                        $(this).destroy();
27921                    });
27922                }
27923
27924                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
27925                iscrollHandler.iScrollInstances.push(iScrollInstance);
27926
27927                //off by default until the section gets active
27928                iScrollInstance.wheelOff();
27929
27930                $this.data('iscrollInstance', iScrollInstance);
27931            });
27932        },
27933
27934        /**
27935         * Return a boolean depending on whether the scrollable element is a
27936         * the end or at the start of the scrolling depending on the given type.
27937         *
27938         * @param  {String}  type       Either 'top' or 'bottom'
27939         * @param  {Object}  scrollable jQuery object for the scrollable element
27940         * @return {Boolean}
27941         */
27942        isScrolled: function(type, scrollable) {
27943            var scroller = scrollable.data('iscrollInstance');
27944
27945            //no scroller?
27946            if (!scroller) {
27947                return true;
27948            }
27949
27950            if (type === 'top') {
27951                return scroller.y >= 0 && !scrollable.scrollTop();
27952            } else if (type === 'bottom') {
27953                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
27954            }
27955        },
27956
27957        /**
27958         * Returns the scrollable element for the given section.
27959         * If there are landscape slides, will only return a scrollable element
27960         * if it is in the active slide.
27961         *
27962         * @param  {Object}  activeSection jQuery object containing current section
27963         * @return {Boolean}
27964         */
27965        scrollable: function(activeSection){
27966            // if there are landscape slides, we check if the scrolling bar is in the current one or not
27967            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
27968                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
27969            }
27970            return activeSection.find(SCROLLABLE_SEL);
27971        },
27972
27973        /**
27974         * Returns the scroll height of the wrapped content.
27975         * If this is larger than the window height minus section padding,
27976         * overflow scrolling is needed.
27977         *
27978         * @param  {Object} element jQuery object containing current section
27979         * @return {Number}
27980         */
27981        scrollHeight: function(element) {
27982            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
27983        },
27984
27985        /**
27986         * Called when overflow scrolling is no longer needed for a section.
27987         *
27988         * @param  {Object} element      jQuery object containing current section
27989         */
27990        remove: function(element) {
27991            var scrollable = element.find(SCROLLABLE_SEL);
27992            if (scrollable.length) {
27993                var iScrollInstance = scrollable.data('iscrollInstance');
27994                iScrollInstance.destroy();
27995
27996                scrollable.data('iscrollInstance', null);
27997            }
27998            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
27999        },
28000
28001        /**
28002         * Called when overflow scrolling has already been setup but the
28003         * window height has potentially changed.
28004         *
28005         * @param  {Object}
vendor: 16,384 bytes, lines 28005-28556
28005 element      jQuery object containing current section
28006         * @param  {Number} scrollHeight Current window height in pixels
28007         */
28008        update: function(element, scrollHeight) {
28009            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
28010            //short period of time.
28011            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
28012            clearTimeout(iscrollHandler.refreshId);
28013            iscrollHandler.refreshId = setTimeout(function(){
28014                $.each(iscrollHandler.iScrollInstances, function(){
28015                    $(this).get(0).refresh();
28016                });
28017            }, 150);
28018
28019            //updating the wrappers height
28020            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
28021        },
28022
28023        /**
28024         * Called to get any additional elements needed to wrap the section
28025         * content in order to facilitate overflow scrolling.
28026         *
28027         * @return {String|Object} Can be a string containing HTML,
28028         *                         a DOM element, or jQuery object.
28029         */
28030        wrapContent: function() {
28031            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
28032        }
28033    };
28034});
28035
28036/* ========================================================================
28037 * Bootstrap: collapse.js v3.1.1
28038 * http://getbootstrap.com/javascript/#collapse
28039 * ========================================================================
28040 * Copyright 2011-2014 Twitter, Inc.
28041 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28042 * ======================================================================== */
28043
28044
28045+function ($) {
28046	'use strict';
28047
28048	// COLLAPSE PUBLIC CLASS DEFINITION
28049	// ================================
28050
28051	var Collapse = function (element, options) {
28052		this.$element      = $(element)
28053		this.options       = $.extend({}, Collapse.DEFAULTS, options)
28054		this.transitioning = null
28055
28056		if (this.options.parent) this.$parent = $(this.options.parent)
28057		if (this.options.toggle) this.toggle()
28058	}
28059
28060	Collapse.DEFAULTS = {
28061		toggle: true
28062	}
28063
28064	Collapse.prototype.dimension = function () {
28065		var hasWidth = this.$element.hasClass('width')
28066		return hasWidth ? 'width' : 'height'
28067	}
28068
28069	Collapse.prototype.show = function () {
28070		if (this.transitioning || this.$element.hasClass('in')) return
28071
28072		var startEvent = $.Event('show.bs.collapse')
28073		this.$element.trigger(startEvent)
28074		if (startEvent.isDefaultPrevented()) return
28075
28076		var actives = this.$parent && this.$parent.find('> .panel > .in')
28077
28078		if (actives && actives.length) {
28079			var hasData = actives.data('bs.collapse')
28080			if (hasData && hasData.transitioning) return
28081			actives.collapse('hide')
28082			hasData || actives.data('bs.collapse', null)
28083		}
28084
28085		var dimension = this.dimension()
28086
28087		this.$element
28088			.removeClass('collapse')
28089			.addClass('collapsing')[dimension](0)
28090
28091		this.transitioning = 1
28092
28093		var complete = function (e) {
28094			if (e && e.target != this.$element[0]) return
28095			this.$element
28096				.removeClass('collapsing')
28097				.addClass('collapse in')[dimension]('auto')
28098			this.transitioning = 0
28099			this.$element.trigger('shown.bs.collapse')
28100		}
28101
28102		if (!$.support.transition) return complete.call(this)
28103
28104		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
28105
28106		this.$element
28107			.one($.support.transition.end, $.proxy(complete, this))
28108			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
28109	}
28110
28111	Collapse.prototype.hide = function () {
28112		if (this.transitioning || !this.$element.hasClass('in')) return
28113
28114		var startEvent = $.Event('hide.bs.collapse')
28115		this.$element.trigger(startEvent)
28116		if (startEvent.isDefaultPrevented()) return
28117
28118		var dimension = this.dimension()
28119
28120		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
28121
28122		this.$element
28123			.addClass('collapsing')
28124			.removeClass('collapse')
28125			.removeClass('in')
28126
28127		this.transitioning = 1
28128
28129		var complete = function (e) {
28130			if (e && e.target != this.$element[0]) return
28131			this.transitioning = 0
28132			this.$element
28133				.trigger('hidden.bs.collapse')
28134				.removeClass('collapsing')
28135				.addClass('collapse')
28136		}
28137
28138		if (!$.support.transition) return complete.call(this)
28139
28140		this.$element
28141			[dimension](0)
28142			.one($.support.transition.end, $.proxy(complete, this))
28143			.emulateTransitionEnd(350)
28144	}
28145
28146	Collapse.prototype.toggle = function () {
28147		this[this.$element.hasClass('in') ? 'hide' : 'show']()
28148	}
28149
28150
28151	// COLLAPSE PLUGIN DEFINITION
28152	// ==========================
28153
28154	var old = $.fn.collapse
28155
28156	$.fn.collapse = function (option) {
28157		return this.each(function () {
28158			var $this   = $(this)
28159			var data    = $this.data('bs.collapse')
28160			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
28161
28162			if (!data && options.toggle && option == 'show') option = !option
28163			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
28164			if (typeof option == 'string') data[option]()
28165		})
28166	}
28167
28168	$.fn.collapse.Constructor = Collapse
28169
28170
28171	// COLLAPSE NO CONFLICT
28172	// ====================
28173
28174	$.fn.collapse.noConflict = function () {
28175		$.fn.collapse = old
28176		return this
28177	}
28178
28179
28180	// COLLAPSE DATA-API
28181	// =================
28182
28183	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
28184		var $this   = $(this), href
28185		var target  = $this.attr('data-target')
28186				|| e.preventDefault()
28187				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
28188		//Edited by Uncode to replace ID in panel [START]
28189		var _target = href.replace(/^#/, "");
28190		if ( $('[data-id="' + _target + '"]').length ) {
28191			var $target = $('[data-id="' + _target + '"]')
28192		} else {
28193			var $target = $(target)
28194		}
28195		//Edited by Uncode to replace ID in panel [END]
28196		var data    = $target.data('bs.collapse')
28197		var option  = data ? 'toggle' : $this.data()
28198		var parent  = $this.attr('data-parent')
28199		var $parent = parent && $(parent)
28200
28201		if (!data || !data.transitioning) {
28202			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
28203			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
28204		}
28205
28206		$target.collapse(option)
28207	})
28208
28209}(jQuery);
28210
28211/* ========================================================================
28212 * Bootstrap: tab.js v3.1.1
28213 * http://getbootstrap.com/javascript/#tabs
28214 * ========================================================================
28215 * Copyright 2011-2014 Twitter, Inc.
28216 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28217 * ======================================================================== */
28218
28219
28220+function ($) {
28221  'use strict';
28222
28223  // TAB CLASS DEFINITION
28224  // ====================
28225
28226  var Tab = function (element) {
28227    this.element = $(element)
28228  }
28229
28230  Tab.prototype.show = function () {
28231    var $this    = this.element
28232    var $ul      = $this.closest('ul:not(.dropdown-menu)')
28233    var selector = $this.data('target')
28234
28235    if (!selector) {
28236      selector = $this.attr('href')
28237      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
28238    }
28239
28240    if ($this.parent('li').hasClass('active')) return
28241
28242    var previous = $ul.find('.active:last a')[0]
28243    var e        = $.Event('show.bs.tab', {
28244      relatedTarget: previous
28245    })
28246
28247    $this.trigger(e)
28248
28249    if (e.isDefaultPrevented()) return
28250
28251    //Edited by Uncode to replace ID in panel [START]
28252    var _target = selector.replace(/^#/, "");
28253    if ( $('[data-id="' + _target + '"]').length )
28254      var $target = $('[data-id="' + _target + '"]')
28255    else
28256      var $target = $(selector)
28257    //Edited by Uncode to replace ID in panel [END]
28258
28259    this.activate($this.parent('li'), $ul)
28260    this.activate($target, $target.parent(), function () {
28261      $this.trigger({
28262        type: 'shown.bs.tab',
28263        relatedTarget: previous
28264      })
28265    })
28266  }
28267
28268  Tab.prototype.activate = function (element, container, callback) {
28269    var $active    = container.find('> .active')
28270    var transition = callback
28271      && $.support.transition
28272      && $active.hasClass('fade')
28273
28274    function next() {
28275      $active
28276        .removeClass('active')
28277        .find('> .dropdown-menu > .active')
28278        .removeClass('active')
28279
28280      element.addClass('active')
28281
28282      if (transition) {
28283        element[0].offsetWidth // reflow for transition
28284        element.addClass('in')
28285      } else {
28286        element.removeClass('fade')
28287      }
28288
28289      if (element.parent('.dropdown-menu')) {
28290        element.closest('li.dropdown').addClass('active')
28291      }
28292
28293      callback && callback()
28294    }
28295
28296    transition ?
28297      $active
28298        .one($.support.transition.end, next)
28299        .emulateTransitionEnd(150) :
28300      next()
28301
28302    $active.removeClass('in')
28303  }
28304
28305
28306  // TAB PLUGIN DEFINITION
28307  // =====================
28308
28309  var old = $.fn.tab
28310
28311  $.fn.tab = function ( option ) {
28312    return this.each(function () {
28313      var $this = $(this)
28314      var data  = $this.data('bs.tab')
28315
28316      if (!data) $this.data('bs.tab', (data = new Tab(this)))
28317      if (typeof option == 'string') data[option]()
28318    })
28319  }
28320
28321  $.fn.tab.Constructor = Tab
28322
28323
28324  // TAB NO CONFLICT
28325  // ===============
28326
28327  $.fn.tab.noConflict = function () {
28328    $.fn.tab = old
28329    return this
28330  }
28331
28332
28333  // TAB DATA-API
28334  // ============
28335
28336  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
28337    e.preventDefault()
28338    $(this).tab('show')
28339  })
28340
28341}(jQuery);
28342
28343/* ========================================================================
28344 * Bootstrap: tooltip.js v3.1.1
28345 * http://getbootstrap.com/javascript/#tooltip
28346 * Inspired by the original jQuery.tipsy by Jason Frame
28347 * ========================================================================
28348 * Copyright 2011-2014 Twitter, Inc.
28349 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28350 * ======================================================================== */
28351
28352
28353+function ($) {
28354  'use strict';
28355
28356  // TOOLTIP PUBLIC CLASS DEFINITION
28357  // ===============================
28358
28359  var Tooltip = function (element, options) {
28360    this.type       =
28361    this.options    =
28362    this.enabled    =
28363    this.timeout    =
28364    this.hoverState =
28365    this.$element   = null
28366
28367    this.init('tooltip', element, options)
28368  }
28369
28370  Tooltip.DEFAULTS = {
28371    animation: true,
28372    placement: 'top',
28373    selector: false,
28374    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
28375    trigger: 'hover focus',
28376    title: '',
28377    delay: 0,
28378    html: false,
28379    container: false,
28380    viewport: {
28381      selector: 'body',
28382      padding: 0
28383    }
28384  }
28385
28386  Tooltip.prototype.init = function (type, element, options) {
28387    this.enabled   = true
28388    this.type      = type
28389    this.$element  = $(element)
28390    this.options   = this.getOptions(options)
28391    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
28392
28393    var triggers = this.options.trigger.split(' ')
28394
28395    for (var i = triggers.length; i--;) {
28396      var trigger = triggers[i]
28397
28398      if (trigger == 'click') {
28399        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
28400      } else if (trigger != 'manual') {
28401        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
28402        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
28403
28404        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
28405        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
28406      }
28407    }
28408
28409    this.options.selector ?
28410      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
28411      this.fixTitle()
28412  }
28413
28414  Tooltip.prototype.getDefaults = function () {
28415    return Tooltip.DEFAULTS
28416  }
28417
28418  Tooltip.prototype.getOptions = function (options) {
28419    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
28420
28421    if (options.delay && typeof options.delay == 'number') {
28422      options.delay = {
28423        show: options.delay,
28424        hide: options.delay
28425      }
28426    }
28427
28428    return options
28429  }
28430
28431  Tooltip.prototype.getDelegateOptions = function () {
28432    var options  = {}
28433    var defaults = this.getDefaults()
28434
28435    this._options && $.each(this._options, function (key, value) {
28436      if (defaults[key] != value) options[key] = value
28437    })
28438
28439    return options
28440  }
28441
28442  Tooltip.prototype.enter = function (obj) {
28443    var self = obj instanceof this.constructor ?
28444      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
28445
28446    clearTimeout(self.timeout)
28447
28448    self.hoverState = 'in'
28449
28450    if (!self.options.delay || !self.options.delay.show) return self.show()
28451
28452    self.timeout = setTimeout(function () {
28453      if (self.hoverState == 'in') self.show()
28454    }, self.options.delay.show)
28455  }
28456
28457  Tooltip.prototype.leave = function (obj) {
28458    var self = obj instanceof this.constructor ?
28459      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
28460
28461    clearTimeout(self.timeout)
28462
28463    self.hoverState = 'out'
28464
28465    if (!self.options.delay || !self.options.delay.hide) return self.hide()
28466
28467    self.timeout = setTimeout(function () {
28468      if (self.hoverState == 'out') self.hide()
28469    }, self.options.delay.hide)
28470  }
28471
28472  Tooltip.prototype.show = function () {
28473    var e = $.Event('show.bs.' + this.type)
28474
28475    if (this.hasContent() && this.enabled) {
28476      this.$element.trigger(e)
28477
28478      if (e.isDefaultPrevented()) return
28479      var that = this;
28480
28481      var $tip = this.tip()
28482
28483      this.setContent()
28484
28485      if (this.options.animation) $tip.addClass('fade')
28486
28487      var placement = typeof this.options.placement == 'function' ?
28488        this.options.placement.call(this, $tip[0], this.$element[0]) :
28489        this.options.placement
28490
28491      var autoToken = /\s?auto?\s?/i
28492      var autoPlace = autoToken.test(placement)
28493      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
28494
28495      $tip
28496        .detach()
28497        .css({ top: 0, left: 0, display: 'block' })
28498        .addClass(placement)
28499
28500      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
28501
28502      var pos          = this.getPosition()
28503      var actualWidth  = $tip[0].offsetWidth
28504      var actualHeight = $tip[0].offsetHeight
28505
28506      if (autoPlace) {
28507        var orgPlacement = placement
28508        var $parent      = this.$element.parent()
28509        var parentDim    = this.getPosition($parent)
28510
28511        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
28512                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
28513                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
28514                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
28515                    placement
28516
28517        $tip
28518          .removeClass(orgPlacement)
28519          .addClass(placement)
28520      }
28521
28522      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
28523
28524      this.applyPlacement(calculatedOffset, placement)
28525      this.hoverState = null
28526
28527      var complete = function() {
28528        that.$element.trigger('shown.bs.' + that.type)
28529      }
28530
28531      $.support.transition && this.$tip.hasClass('fade') ?
28532        $tip
28533          .one($.support.transition.end, complete)
28534          .emulateTransitionEnd(150) :
28535        complete()
28536    }
28537  }
28538
28539  Tooltip.prototype.applyPlacement = function (offset, placement) {
28540    var $tip   = this.tip()
28541    var width  = $tip[0].offsetWidth
28542    var height = $tip[0].offsetHeight
28543
28544    // manually read margins because getBoundingClientRect includes difference
28545    var marginTop = parseInt($tip.css('margin-top'), 10)
28546    var marginLeft = parseInt($tip.css('margin-left'), 10)
28547
28548    // we must check for NaN for ie 8/9
28549    if (isNaN(marginTop))  marginTop  = 0
28550    if (isNaN(marginLeft)) marginLeft = 0
28551
28552    offset.top  = offset.top  + marginTop
28553    offset.left = offset.left + marginLeft
28554
28555    // $.fn.offset doesn't round pixel values
28556    // so we use setOff
28556set directly with our own function B-0
28557    $.offset.setOffset($tip[0], $.extend({
28558      using: function (props) {
28559        $tip.css({
28560          top: Math.round(props.top),
28561          left: Math.round(props.left)
28562        })
28563      }
28564    }, offset), 0)
28565
28566    $tip.addClass('in')
28567
28568    // check to see if placing tip in new offset caused the tip to resize itself
28569    var actualWidth  = $tip[0].offsetWidth
28570    var actualHeight = $tip[0].offsetHeight
28571
28572    if (placement == 'top' && actualHeight != height) {
28573      offset.top = offset.top + height - actualHeight
28574    }
28575
28576    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
28577
28578    if (delta.left) offset.left += delta.left
28579    else offset.top += delta.top
28580
28581    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
28582    var arrowPosition       = delta.left ? 'left'        : 'top'
28583    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
28584
28585    $tip.offset(offset)
28586    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
28587  }
28588
28589  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
28590    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
28591  }
28592
28593  Tooltip.prototype.setContent = function () {
28594    var $tip  = this.tip()
28595    var title = this.getTitle()
28596
28597    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
28598    $tip.removeClass('fade in top bottom left right')
28599  }
28600
28601  Tooltip.prototype.hide = function () {
28602    var that = this
28603    var $tip = this.tip()
28604    var e    = $.Event('hide.bs.' + this.type)
28605
28606    function complete() {
28607      if (that.hoverState != 'in') $tip.detach()
28608      that.$element.trigger('hidden.bs.' + that.type)
28609    }
28610
28611    this.$element.trigger(e)
28612
28613    if (e.isDefaultPrevented()) return
28614
28615    $tip.removeClass('in')
28616
28617    $.support.transition && this.$tip.hasClass('fade') ?
28618      $tip
28619        .one($.support.transition.end, complete)
28620        .emulateTransitionEnd(150) :
28621      complete()
28622
28623    this.hoverState = null
28624
28625    return this
28626  }
28627
28628  Tooltip.prototype.fixTitle = function () {
28629    var $e = this.$element
28630    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
28631      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
28632    }
28633  }
28634
28635  Tooltip.prototype.hasContent = function () {
28636    return this.getTitle()
28637  }
28638
28639  Tooltip.prototype.getPosition = function ($element) {
28640    $element   = $element || this.$element
28641    var el     = $element[0]
28642    var isBody = el.tagName == 'BODY'
28643    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
28644      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
28645      width:  isBody ? $(window).width()  : $element.outerWidth(),
28646      height: isBody ? $(window).height() : $element.outerHeight()
28647    }, isBody ? {top: 0, left: 0} : $element.offset())
28648  }
28649
28650  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
28651    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
28652           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
28653           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
28654        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
28655
28656  }
28657
28658  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
28659    var delta = { top: 0, left: 0 }
28660    if (!this.$viewport) return delta
28661
28662    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
28663    var viewportDimensions = this.getPosition(this.$viewport)
28664
28665    if (/right|left/.test(placement)) {
28666      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
28667      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
28668      if (topEdgeOffset < viewportDimensions.top) { // top overflow
28669        delta.top = viewportDimensions.top - topEdgeOffset
28670      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
28671        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
28671EdgeOffset
28672      }
28673    } else {
28674      var leftEdgeOffset  = pos.left - viewportPadding
28675      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
28676      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
28677        delta.left = viewportDimensions.left - leftEdgeOffset
28678      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
28679        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
28680      }
28681    }
28682
28683    return delta
28684  }
28685
28686  Tooltip.prototype.getTitle = function () {
28687    var title
28688    var $e = this.$element
28689    var o  = this.options
28690
28691    title = $e.attr('data-original-title')
28692      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
28693
28694    return title
28695  }
28696
28697  Tooltip.prototype.tip = function () {
28698    return this.$tip = this.$tip || $(this.options.template)
28699  }
28700
28701  Tooltip.prototype.arrow = function () {
28702    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
28703  }
28704
28705  Tooltip.prototype.validate = function () {
28706    if (!this.$element[0].parentNode) {
28707      this.hide()
28708      this.$element = null
28709      this.options  = null
28710    }
28711  }
28712
28713  Tooltip.prototype.enable = function () {
28714    this.enabled = true
28715  }
28716
28717  Tooltip.prototype.disable = function () {
28718    this.enabled = false
28719  }
28720
28721  Tooltip.prototype.toggleEnabled = function () {
28722    this.enabled = !this.enabled
28723  }
28724
28725  Tooltip.prototype.toggle = function (e) {
28726    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
28727    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
28728  }
28729
28730  Tooltip.prototype.destroy = function () {
28731    clearTimeout(this.timeout)
28732    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
28733  }
28734
28735
28736  // TOOLTIP PLUGIN DEFINITION
28737  // =========================
28738
28739  var old = $.fn.tooltip
28740
28741  $.fn.tooltip = function (option) {
28742    return this.each(function () {
28743      var $this   = $(this)
28744      var data    = $this.data('bs.tooltip')
28745      var options = typeof option == 'object' && option
28746
28747      if (!data && option == 'destroy') return
28748      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
28749      if (typeof option == 'string') data[option]()
28750    })
28751  }
28752
28753  $.fn.tooltip.Constructor = Tooltip
28754
28755
28756  // TOOLTIP NO CONFLICT
28757  // ===================
28758
28759  $.fn.tooltip.noConflict = function () {
28760    $.fn.tooltip = old
28761    return this
28762  }
28763
28764}(jQuery);
28765
28766/* ========================================================================
28767 * Bootstrap: transition.js v3.1.1
28768 * http://getbootstrap.com/javascript/#transitions
28769 * ========================================================================
28770 * Copyright 2011-2014 Twitter, Inc.
28771 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28772 * ======================================================================== */
28773
28774
28775+function ($) {
28776  'use strict';
28777
28778  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
28779  // ============================================================
28780
28781  function transitionEnd() {
28782    var el = document.createElement('bootstrap')
28783
28784    var transEndEventNames = {
28785      WebkitTransition : 'webkitTransitionEnd',
28786      MozTransition    : 'transitionend',
28787      OTransition      : 'oTransitionEnd otransitionend',
28788      transition       : 'transitionend'
28789    }
28790
28791    for (var name in transEndEventNames) {
28792      if (el.style[name] !== undefined) {
28793        return { end: transEndEventNames[name] }
28794      }
28795    }
28796
28797    return false // explicit for ie8 (  ._.)
28798  }
28799
28800  // http://blog.alexmaccaw.com/css-transitions
28801  $.fn.emulateTransitionEnd = function (duration) {
28802    var called = false, $el = this
28803    $(this).one($.support.transition.end, function () { called = true })
28804    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
28805    setTimeout(callback, duration)
28806    return this
28807  }
28808
28809  $(function () {
28810    $.support.transition = transitionEnd()
28811  })
28812
28813}(jQuery);
28814
28815
28816// ------------------------------------------
28817// Rellax.js
28818// Buttery smooth parallax library
28819// Copyright (c) 2016 Moe Amaya (@moeamaya)
28820// MIT license
28821//
28822// Thanks to Paraxify.js and Jaime Cabllero
28823// for parallax concepts
28824// ------------------------------------------
28825
28826(function (root, factory) {
28827	if (typeof define === 'function' && define.amd) {
28828		// AMD. Register as an anonymous module.
28829		define([], factory);
28830	} else if (typeof module === 'object' && module.exports) {
28831		// Node. Does not work with strict CommonJS, but
28832		// only CommonJS-like environments that support module.exports,
28833		// like Node.
28834		module.exports = factory();
28835	} else {
28836		// Browser globals (root is window)
28837		root.Rellax = factory();
28838	}
28839}(typeof window !== "undefined" ? window : global, function () {
28840	var Rellax = function(el, options){
28841		"use strict";
28842
28843		var self = Object.create(Rellax.prototype);
28844
28845		var posY = 0;
28846		var screenY = 0;
28847		var posX = 0;
28848		var screenX = 0;
28849		var blocks = [];
28850		var pause = true;
28851
28852		// check what requestAnimationFrame to use, and if
28853		// it's not supported, use the onscroll event
28854		var loop = window.requestAnimationFrame ||
28855			window.webkitRequestAnimationFrame ||
28856			window.mozRequestAnimationFrame ||
28857			window.msRequestAnimationFrame ||
28858			window.oRequestAnimationFrame ||
28859			function(callback){ return setTimeout(callback, 1000 / 60); };
28860
28861		// store the id for later use
28862		var loopId = null;
28863
28864		// Test via a getter in the options object to see if the passive property is accessed
28865		var supportsPassive = false;
vendor: 16,286 bytes, lines 28866-29311
28866		try {
28867			var opts = Object.defineProperty({}, 'passive', {
28868				get: function() {
28869					supportsPassive = true;
28870				}
28871			});
28872			window.addEventListener("testPassive", null, opts);
28873			window.removeEventListener("testPassive", null, opts);
28874		} catch (e) {}
28875
28876		// check what cancelAnimation method to use
28877		var clearLoop = window.cancelAnimationFrame || window.mozCancelAnimationFrame || clearTimeout;
28878
28879		// check which transform property to use
28880		var transformProp = window.transformProp || (function(){
28881				var testEl = document.createElement('div');
28882				if (testEl.style.transform === null) {
28883					var vendors = ['Webkit', 'Moz', 'ms'];
28884					for (var vendor in vendors) {
28885						if (testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) {
28886							return vendors[vendor] + 'Transform';
28887						}
28888					}
28889				}
28890				return 'transform';
28891			})();
28892
28893		// Default Settings
28894		self.options = {
28895			speed: -2,
28896			verticalSpeed: null,
28897			horizontalSpeed: null,
28898			breakpoints: [576, 768, 1201],
28899			center: false,
28900			wrapper: null,
28901			relativeToWrapper: false,
28902			round: true,
28903			vertical: true,
28904			horizontal: false,
28905			verticalScrollAxis: "y",
28906			horizontalScrollAxis: "x",
28907			callback: function() {},
28908		};
28909
28910		// User defined options (might have more in the future)
28911		if (options){
28912			Object.keys(options).forEach(function(key){
28913				self.options[key] = options[key];
28914			});
28915		}
28916
28917		function validateCustomBreakpoints () {
28918			if (self.options.breakpoints.length === 3 && Array.isArray(self.options.breakpoints)) {
28919				var isAscending = true;
28920				var isNumerical = true;
28921				var lastVal;
28922				self.options.breakpoints.forEach(function (i) {
28923					if (typeof i !== 'number') isNumerical = false;
28924					if (lastVal !== null) {
28925						if (i < lastVal) isAscending = false;
28926					}
28927					lastVal = i;
28928				});
28929				if (isAscending && isNumerical) return;
28930			}
28931			// revert defaults if set incorrectly
28932			self.options.breakpoints = [576, 768, 1201];
28933			console.warn("Rellax: You must pass an array of 3 numbers in ascending order to the breakpoints option. Defaults reverted");
28934		}
28935
28936		if (options && options.breakpoints) {
28937			validateCustomBreakpoints();
28938		}
28939
28940		// By default, rellax class
28941		if (!el) {
28942			el = '.rellax';
28943		}
28944
28945		// check if el is a className or a node
28946		var elements = typeof el === 'string' ? document.querySelectorAll(el) : [el];
28947
28948		// Now query selector
28949		if (elements.length > 0) {
28950			self.elems = elements;
28951		}
28952
28953		// The elements don't exist
28954		else {
28955			console.warn("Rellax: The elements you're trying to select don't exist.");
28956			return;
28957		}
28958
28959		// Has a wrapper and it exists
28960		if (self.options.wrapper) {
28961			if (!self.options.wrapper.nodeType) {
28962				var wrapper = document.querySelector(self.options.wrapper);
28963
28964				if (wrapper) {
28965					self.options.wrapper = wrapper;
28966				} else {
28967					console.warn("Rellax: The wrapper you're trying to use doesn't exist.");
28968					return;
28969				}
28970			}
28971		}
28972
28973		// set a placeholder for the current breakpoint
28974		var currentBreakpoint;
28975
28976		// helper to determine current breakpoint
28977		var getCurrentBreakpoint = function (w) {
28978			var bp = self.options.breakpoints;
28979			if (w < bp[0]) return 'xs';
28980			if (w >= bp[0] && w < bp[1]) return 'sm';
28981			if (w >= bp[1] && w < bp[2]) return 'md';
28982			return 'lg';
28983		};
28984
28985		// Get and cache initial position of all elements
28986		var cacheBlocks = function() {
28987			for (var i = 0; i < self.elems.length; i++){
28988				var block = createBlock(self.elems[i]);
28989				blocks.push(block);
28990			}
28991		};
28992
28993
28994		// Let's kick this script off
28995		// Build array for cached element values
28996		var init = function() {
28997			for (var i = 0; i < blocks.length; i++){
28998				self.elems[i].style.cssText = blocks[i].style;
28999			}
29000
29001			blocks = [];
29002
29003			screenY = window.innerHeight;
29004			screenX = window.innerWidth;
29005			currentBreakpoint = getCurrentBreakpoint(screenX);
29006
29007			setPosition();
29008
29009			cacheBlocks();
29010
29011			animate();
29012
29013			// If paused, unpause and set listener for window resizing events
29014			if (pause) {
29015				window.addEventListener('resize', init);
29016				pause = false;
29017				// Start the loop
29018				update();
29019			}
29020		};
29021
29022		// We want to cache the parallax blocks'
29023		// values: base, top, height, speed
29024		// el: is dom object, return: el cache values
29025		var createBlock = function(el) {
29026			var dataPercentage = el.getAttribute( 'data-rellax-percentage' );
29027			var dataSpeed = el.getAttribute( 'data-rellax-speed' );
29028			var dataXsSpeed = el.getAttribute( 'data-rellax-xs-speed' );
29029			var dataMobileSpeed = el.getAttribute( 'data-rellax-mobile-speed' );
29030			var dataTabletSpeed = el.getAttribute( 'data-rellax-tablet-speed' );
29031			var dataDesktopSpeed = el.getAttribute( 'data-rellax-desktop-speed' );
29032			var dataVerticalSpeed = el.getAttribute('data-rellax-vertical-speed');
29033			var dataHorizontalSpeed = el.getAttribute('data-rellax-horizontal-speed');
29034			var dataVericalScrollAxis = el.getAttribute('data-rellax-vertical-scroll-axis');
29035			var dataHorizontalScrollAxis = el.getAttribute('data-rellax-horizontal-scroll-axis');
29036			var dataZindex = el.getAttribute( 'data-rellax-zindex' ) || 0;
29037			var dataMin = el.getAttribute( 'data-rellax-min' );
29038			var dataMax = el.getAttribute( 'data-rellax-max' );
29039			var dataMinX = el.getAttribute('data-rellax-min-x');
29040			var dataMaxX = el.getAttribute('data-rellax-max-x');
29041			var dataMinY = el.getAttribute('data-rellax-min-y');
29042			var dataMaxY = el.getAttribute('data-rellax-max-y');
29043			var mapBreakpoints;
29044			var breakpoints = true;
29045
29046			if (!dataXsSpeed && !dataMobileSpeed && !dataTabletSpeed && !dataDesktopSpeed) {
29047				breakpoints = false;
29048			} else {
29049				mapBreakpoints = {
29050					'xs': dataXsSpeed,
29051					'sm': dataMobileSpeed,
29052					'md': dataTabletSpeed,
29053					'lg': dataDesktopSpeed
29054				};
29055			}
29056
29057			// initializing at scrollY = 0 (top of browser), scrollX = 0 (left of browser)
29058			// ensures elements are positioned based on HTML layout.
29059			//
29060			// If the element has the percentage attribute, the posY and posX needs to be
29061			// the current scroll position's value, so that the elements are still positioned based on HTML layout
29062			var wrapperPosY = self.options.wrapper ? self.options.wrapper.scrollTop : (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
29063			// If the option relativeToWrapper is true, use the wrappers offset to top, subtracted from the current page scroll.
29064			if (self.options.relativeToWrapper) {
29065				var scrollPosY = (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
29066				wrapperPosY = scrollPosY - self.options.wrapper.offsetTop;
29067			}
29068			var posY = self.options.vertical ? ( dataPercentage || self.options.center ? wrapperPosY : 0 ) : 0;
29069			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;
29070
29071			var blockTop = posY + el.getBoundingClientRect().top;
29072			var blockHeight = el.clientHeight || el.offsetHeight || el.scrollHeight;
29073
29074			var blockLeft = posX + el.getBoundingClientRect().left;
29075			var blockWidth = el.clientWidth || el.offsetWidth || el.scrollWidth;
29076
29077			// apparently parallax equation everyone uses
29078			var percentageY = dataPercentage ? dataPercentage : (posY - blockTop + screenY) / (blockHeight + screenY);
29079			var percentageX = dataPercentage ? dataPercentage : (posX - blockLeft + screenX) / (blockWidth + screenX);
29080			if(self.options.center){ percentageX = 0.5; percentageY = 0.5; }
29081
29082			// Optional individual block speed as data attr, otherwise global speed
29083			var speed = (breakpoints && mapBreakpoints[currentBreakpoint] !== null) ? Number(mapBreakpoints[currentBreakpoint]) : (dataSpeed ? dataSpeed : self.options.speed);
29084			var verticalSpeed = dataVerticalSpeed ? dataVerticalSpeed : self.options.verticalSpeed;
29085			var horizontalSpeed = dataHorizontalSpeed ? dataHorizontalSpeed : self.options.horizontalSpeed;
29086
29087			// Optional individual block movement axis direction as data attr, otherwise global movement direction
29088			var verticalScrollAxis = dataVericalScrollAxis ? dataVericalScrollAxis : self.options.verticalScrollAxis;
29089			var horizontalScrollAxis = dataHorizontalScrollAxis ? dataHorizontalScrollAxis : self.options.horizontalScrollAxis;
29090
29091			var bases = updatePosition(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed);
29092
29093			// ~~Store non-translate3d transforms~~
29094			// Store inline styles and extract transforms
29095			var style = el.style.cssText;
29096			var transform = '';
29097
29098			// Check if there's an inline styled transform
29099			var searchResult = /transform\s*:/i.exec(style);
29100			if (searchResult) {
29101				// Get the index of the transform
29102				var index = searchResult.index;
29103
29104				// Trim the style to the transform point and get the following semi-colon index
29105				var trimmedStyle = style.slice(index);
29106				var delimiter = trimmedStyle.indexOf(';');
29107
29108				// Remove "transform" string and save the attribute
29109				if (delimiter) {
29110					transform = " " + trimmedStyle.slice(11, delimiter).replace(/\s/g,'');
29111				} else {
29112					transform = " " + trimmedStyle.slice(11).replace(/\s/g,'');
29113				}
29114			}
29115
29116			return {
29117				baseX: bases.x,
29118				baseY: bases.y,
29119				top: blockTop,
29120				left: blockLeft,
29121				height: blockHeight,
29122				width: blockWidth,
29123				speed: speed,
29124				verticalSpeed: verticalSpeed,
29125				horizontalSpeed: horizontalSpeed,
29126				verticalScrollAxis: verticalScrollAxis,
29127				horizontalScrollAxis: horizontalScrollAxis,
29128				style: style,
29129				transform: transform,
29130				zindex: dataZindex,
29131				min: dataMin,
29132				max: dataMax,
29133				minX: dataMinX,
29134				maxX: dataMaxX,
29135				minY: dataMinY,
29136				maxY: dataMaxY
29137			};
29138		};
29139
29140		// set scroll position (posY, posX)
29141		// side effect method is not ideal, but okay for now
29142		// returns true if the scroll changed, false if nothing happened
29143		var setPosition = function() {
29144			var oldY = posY;
29145			var oldX = posX;
29146
29147			posY = self.options.wrapper ? self.options.wrapper.scrollTop : (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
29148			posX = self.options.wrapper ? self.options.wrapper.scrollLeft : (document.documentElement || document.body.parentNode || document.body).scrollLeft || window.pageXOffset;
29149			// If option relativeToWrapper is true, use relative wrapper value instead.
29150			if (self.options.relativeToWrapper) {
29151				var scrollPosY = (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
29152				posY = scrollPosY - self.options.wrapper.offsetTop;
29153			}
29154
29155
29156			if (oldY != posY && self.options.vertical) {
29157				// scroll changed, return true
29158				return true;
29159			}
29160
29161			if (oldX != posX && self.options.horizontal) {
29162				// scroll changed, return true
29163				return true;
29164			}
29165
29166			// scroll did not change
29167			return false;
29168		};
29169
29170		// Ahh a pure function, gets new transform value
29171		// based on scrollPosition and speed
29172		// Allow for decimal pixel values
29173		var updatePosition = function(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed) {
29174			var result = {};
29175			var valueX = ((horizontalSpeed ? horizontalSpeed : speed) * (100 * (1 - percentageX)));
29176			var valueY = ((verticalSpeed ? verticalSpeed : speed) * (100 * (1 - percentageY)));
29177
29178			result.x = self.options.round ? Math.round(valueX) : Math.round(valueX * 100) / 100;
29179			result.y = self.options.round ? Math.round(valueY) : Math.round(valueY * 100) / 100;
29180
29181			return result;
29182		};
29183
29184		// Remove event listeners and loop again
29185		var deferredUpdate = function() {
29186			window.removeEventListener('resize', deferredUpdate);
29187			window.removeEventListener('orientationchange', deferredUpdate);
29188			(self.options.wrapper ? self.options.wrapper : window).removeEventListener('scroll', deferredUpdate);
29189			(self.options.wrapper ? self.options.wrapper : document).removeEventListener('touchmove', deferredUpdate);
29190
29191			// loop again
29192			loopId = loop(update);
29193		};
29194
29195		// Loop
29196		var update = function() {
29197			if (setPosition() && pause === false) {
29198				animate();
29199
29200				// loop again
29201				loopId = loop(update);
29202			} else {
29203				loopId = null;
29204
29205				// Don't animate until we get a position updating event
29206				window.addEventListener('resize', deferredUpdate);
29207				window.addEventListener('orientationchange', deferredUpdate);
29208				(self.options.wrapper ? self.options.wrapper : window).addEventListener('scroll', deferredUpdate, supportsPassive ? { passive: true } : false);
29209				(self.options.wrapper ? self.options.wrapper : document).addEventListener('touchmove', deferredUpdate, supportsPassive ? { passive: true } : false);
29210			}
29211		};
29212
29213		// Transform3d on parallax element
29214		var animate = function() {
29215			var positions;
29216			for (var i = 0; i < self.elems.length; i++){
29217				// Determine relevant movement directions
29218				var verticalScrollAxis = blocks[i].verticalScrollAxis.toLowerCase();
29219				var horizontalScrollAxis = blocks[i].horizontalScrollAxis.toLowerCase();
29220				var verticalScrollX = verticalScrollAxis.indexOf("x") != -1 ? posY : 0;
29221				var verticalScrollY = verticalScrollAxis.indexOf("y") != -1 ? posY : 0;
29222				var horizontalScrollX = horizontalScrollAxis.indexOf("x") != -1 ? posX : 0;
29223				var horizontalScrollY = horizontalScrollAxis.indexOf("y") != -1 ? posX : 0;
29224
29225				var percentageY = ((verticalScrollY + horizontalScrollY - blocks[i].top + screenY) / (blocks[i].height + screenY));
29226				var percentageX = ((verticalScrollX + horizontalScrollX - blocks[i].left + screenX) / (blocks[i].width + screenX));
29227
29228				// Subtracting initialize value, so element stays in same spot as HTML
29229				positions = updatePosition(percentageX, percentageY, blocks[i].speed, blocks[i].verticalSpeed, blocks[i].horizontalSpeed);
29230				var positionY = positions.y - blocks[i].baseY;
29231				var positionX = positions.x - blocks[i].baseX;
29232
29233				// The next two "if" blocks go like this:
29234				// Check if a limit is defined (first "min", then "max");
29235				// Check if we need to change the Y or the X
29236				// (Currently working only if just one of the axes is enabled)
29237				// Then, check if the new position is inside the allowed limit
29238				// If so, use new position. If not, set position to limit.
29239
29240				// Check if a min limit is defined
29241				if (blocks[i].min !== null) {
29242					if (self.options.vertical && !self.options.horizontal) {
29243						positionY = positionY <= blocks[i].min ? blocks[i].min : positionY;
29244					}
29245					if (self.options.horizontal && !self.options.vertical) {
29246						positionX = positionX <= blocks[i].min ? blocks[i].min : positionX;
29247					}
29248				}
29249
29250				// Check if directional min limits are defined
29251				if (blocks[i].minY != null) {
29252						positionY = positionY <= blocks[i].minY ? blocks[i].minY : positionY;
29253				}
29254				if (blocks[i].minX != null) {
29255						positionX = positionX <= blocks[i].minX ? blocks[i].minX : positionX;
29256				}
29257
29258				// Check if a max limit is defined
29259				if (blocks[i].max !== null) {
29260					if (self.options.vertical && !self.options.horizontal) {
29261						positionY = positionY >= blocks[i].max ? blocks[i].max : positionY;
29262					}
29263					if (self.options.horizontal && !self.options.vertical) {
29264						positionX = positionX >= blocks[i].max ? blocks[i].max : positionX;
29265					}
29266				}
29267
29268				// Check if directional max limits are defined
29269				if (blocks[i].maxY != null) {
29270						positionY = positionY >= blocks[i].maxY ? blocks[i].maxY : positionY;
29271				}
29272				if (blocks[i].maxX != null) {
29273						positionX = positionX >= blocks[i].maxX ? blocks[i].maxX : positionX;
29274				}
29275
29276				var zindex = blocks[i].zindex;
29277
29278				// Move that element
29279				// (Set the new translation and append initial inline transforms.)
29280				var translate = 'translate3d(' + (self.options.horizontal ? positionX : '0') + 'px,' + (self.options.vertical ? positionY : '0') + 'px,' + zindex + 'px) ' + blocks[i].transform;
29281				self.elems[i].style[transformProp] = translate;
29282			}
29283			self.options.callback(positions);
29284		};
29285
29286		self.destroy = function() {
29287			for (var i = 0; i < self.elems.length; i++){
29288				self.elems[i].style.cssText = blocks[i].style;
29289			}
29290
29291			// Remove resize event listener if not pause, and pause
29292			if (!pause) {
29293				window.removeEventListener('resize', init);
29294				pause = true;
29295			}
29296
29297			// Clear the animation loop to prevent possible memory leak
29298			clearLoop(loopId);
29299			loopId = null;
29300		};
29301
29302		// Init
29303		init();
29304
29305		// Allow to recalculate the initial values whenever we want
29306		self.refresh = init;
29307
29308		return self;
29309	};
29310	return Rellax;
29311}));

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.