PageSourceSearch

https://home.appful.io/wp-content/themes/uncode/library/js/plugins.js?ver=829049548

js appful.io collected 2026-09-24 08:37:13 UTC 990,820 bytes, 30,653 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: 11,709 bytes, lines 910-1323
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
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: 22,800 bytes, lines 1973-2719
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) {
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: 32,418 bytes, lines 2993-4050
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) {
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);
vendor: 16,093 bytes, lines 5178-5835
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
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: 75,264 bytes, lines 5838-8743
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() {
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
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
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 space
8960s
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:	false, //'10em',		// min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored
12722		subMenusMaxWidth:	false, //'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		history.replaceState({}, document.title, window.location.pathname + window.location.search);
15585
15586		// Restore the scroll offset, should be flicker free
15587		window.scrollTo(scroll.x, scroll.y);
15588	}
15589
15590	/**
15591	 * Do the ajax requests with callback.
15592	 *
15593	 * @param {String}   url
15594	 * @param {Function} callback
15595	 *
15596	 * @return {Void}
15597	 */
15598	function doAjax(url, callback) {
15599		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');
15600		$.ajax({
15601			url: url,
15602			dataType: 'jsonp'
15603		});
15604
15605		iLCallback = function(data) {
15606			callback.call(this, data);
15607		};
15608	}
15609
15610	/**
15611	 * Find image from DOM elements
15612	 *
15613	 * @param {Element} element
15614	 *
15615	 * @return {Void}
15616	 */
15617	function findImageInElement(element) {
15618		var elements = $('*', element),
15619			imagesArr = new Array();
15620
15621		elements.each(function() {
15622			var url = "",
15623				element = this;
15624
15625			if ($(element).css("background-image") != "none") {
15626				url = $(element).css("background-image");
15627			} else if (typeof($(element).attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") {
15628				url = $(element).attr("src");
15629			}
15630
15631			if (url.indexOf("gradient") == -1) {
15632				url = url.replace(/url\(\"/g, "");
15633				url = url.replace(/url\(/g, "");
15634				url = url.replace(/\"\)/g, "");
15635				url = url.replace(/\)/g, "");
15636
15637				var urls = url.split(",");
15638
15639				for (var i = 0; i < urls.length; i++) {
15640					if (urls[i].length > 0 && $.inArray(urls[i], imagesArr) == -1) {
15641						var extra = "";
15642						if (browser.msie && browser.version < 9) {
15643							extra = "?" + floor(random() * 3000);
15644						}
15645						imagesArr.push(urls[i] + extra);
15646					}
15647				}
15648			}
15649		});
15650
15651		return imagesArr;
15652	}
15653
15654	/**
15655	 * Get file extension.
15656	 *
15657	 * @param {String} URL
15658	 *
15659	 * @return {String}
15660	 */
15661	function getExtension(URL) {
15662		if (URL !== null) {
15663			//UNCODE: fix issue to detect media type with query strings
15664			var ext = URL.indexOf('?') !== -1 ? URL.split('?')[0] : URL;
15665			ext = ext.split('.').pop().toLowerCase();
15666
15667			return ext;
15668		}
15669	}
15670
15671	/**
15672	 * Get type via extension.
15673	 *
15674	 * @param {String} URL
15675	 *
15676	 * @return {String}
15677	 */
15678	function getTypeByExtension(URL) {
15679		var type,
15680			ext = getExtension(URL);
15681
15682		//Uncode addition ##START##
15683		if (URL == undefined) {
15684			return false;
15685		}
15686		//Uncode addition ##END##
15687
15688		if (extensions.image.indexOf(ext) !== -1) type = 'image';
15689		else if (extensions.flash.indexOf(ext) !== -1) type = 'flash';
15690		else if (extensions.video.indexOf(ext) !== -1) type = 'video';
15691		else if (ext.substring(0, 1) == "#") type = 'inline'; //Uncode addition
15692		else type = 'iframe';
15693
15694		return type;
15695	}
15696
15697	/**
15698	 * Return value from percent of a number.
15699	 *
15700	 * @param {Number} percent
15701	 * @param {Number} total
15702	 *
15703	 * @return {Number}
15704	 */
15705	function percentToValue(percent, total) {
15706		return parseInt((total / 100) * percent);
15707	}
15708
15709	/**
15710	 * A JavaScript equivalent of PHP’s parse_url.
15711	 *
15712	 * @param {String} url           The URL to parse.
15713	 *
15714	 * @return {Mixed}
15715	 */
15716	function parseURI(url) {
15717		var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
15718		// authority = '//' + user + ':' + pass '@' + hostname + ':' port
15719		return (m ? {
15720			href: m[0] || '',
15721			protocol: m[1] || '',
15722			authority: m[2] || '',
15723			host: m[3] || '',
15724			hostname: m[4] || '',
15725			port: m[5] || '',
15726			pathname: m[6] || '',
15727			search: m[7] || '',
15728			hash: m[8] || ''
15729		} : null);
15730	}
15731
15732	/**
15733	 * Gets the absolute URI.
15734	 *
15735	 * @param {String} href     The relative URL.
15736	 * @param {String} base     The base URL.
15737	 *
15738	 * @return {String}         The absolute URL.
15739	 */
15740	function absolutizeURI(base, href) { // RFC 3986
15741		var iL = this;
15742
15743		function removeDotSegments(input) {
15744			var output = [];
15745			input.replace(/^(\.\.?(\/|$))+/, '')
15746				.replace(/\/(\.(\/|$))+/g, '/')
15747				.replace(/\/\.\.$/, '/../')
15748				.replace(/\/?[^\/]*/g, function(p) {
15749					if (p === '/..') {
15750						output.pop();
15751					} else {
15752						output.push(p);
15753					}
15754				});
15755			return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
15756		}
15757
15758		href = parseURI(href || '');
15759		base = parseURI(base || '');
15760
15761		return !href || !base ? null : (href.protocol || base.protocol) +
15762			(href.protocol || href.authority ? href.authority : base.authority) +
15763			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)) +
15764			(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
15765			href.hash;
15766	}
15767
15768	/**
15769	 * A JavaScript equivalent of PHP’s version_compare.
15770	 *
15771	 * @param {String} v1
15772	 * @param {String} v2
15773	 * @param {String} operator
15774	 *
15775	 * @return {Boolean}
15776	 */
15777	function version_compare(v1, v2, operator) {
15778		this.php_js = this.php_js || {};
15779		this.php_js.ENV = this.php_js.ENV || {};
15780		var i = 0,
15781			x = 0,
15782			compare = 0,
15783			vm = {
15784				'dev': -6,
15785				'alpha': -5,
15786				'a': -5,
15787				'beta': -4,
15788				'b': -4,
15789				'RC': -3,
15790				'rc': -3,
15791				'#': -2,
15792				'p': 1,
15793				'pl': 1
15794			},
15795			prepVersion = function(v) {
15796				v = ('' + v).replace(/[_\-+]/g, '.');
15797				v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
15798				return (!v.length ? [-8] : v.split('.'));
15799			},
15800			numVersion = function(v) {
15801				return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
15802			};
15803		v1 = prepVersion(v1);
15804		v2 = prepVersion(v2);
15805		x = max(v1.length, v2.length);
15806		for (i = 0; i < x; i++) {
15807			if (v1[i] == v2[i]) {
15808				continue;
15809			}
15810			v1[i] = numVersion(v1[i]);
15811			v2[i] = numVersion(v2[i]);
15812			if (v1[i] < v2[i]) {
15813				compare = -1;
15814				break;
15815			} else if (v1[i] > v2[i]) {
15816				compare = 1;
15817				break;
15818			}
15819		}
15820		if (!operator) {
15821			return compare;
15822		}
15823
15824		switch (operator) {
15825			case '>':
15826			case 'gt':
15827				return (compare > 0);
15828			case '>=':
15829			case 'ge':
15830				return (compare >= 0);
15831			case '<=':
15832			case 'le':
15833				return (compare <= 0);
15834			case '==':
15835			case '=':
15836			case 'eq':
15837				return (compare === 0);
15838			case '<>':
15839			case '!=':
15840			case 'ne':
15841				return (compare !== 0);
15842			case '':
15843			case '<':
15844			case 'lt':
15845				return (compare < 0);
15846			default:
15847				return null;
15848		}
15849	}
15850
15851
15852	// Begin the iLightBox plugin
15853	$.fn.iLightBox = function() {
15854
15855		var args = arguments,
15856			opt = ($.isPlainObject(args[0])) ? args[0] : args[1],
15857			items = ($.isArray(args[0]) || typeof args[0] == 'string') ? args[0] : args[1];
15858
15859		if (!opt) opt = {};
15860
15861		// Default options. Play carefully.
15862		var options = $.extend(true, {
15863			attr: 'href',
15864			path: 'vertical',
15865			skin: 'dark',
15866			linkId: false,
15867			infinite: false,
15868			startFrom: 0,
15869			randomStart: false,
15870			keepAspectRatio: true,
15871			maxScale: 1,
15872			minScale: .2,
15873			innerToolbar: false,
15874			smartRecognition: false,
15875			mobileOptimizer: true,
15876			fullAlone: true,
15877			fullViewPort: null,
15878			fullStretchTypes: 'flash, video',
15879			overlay: {
15880				blur: true,
15881				opacity: .85
15882			},
15883			controls: {
15884				arrows: false,
15885				slideshow: false,
15886				toolbar: true,
15887				fullscreen: true,
15888				thumbnail: true,
15889				keyboard: true,
15890				mousewheel: true,
15891				swipe: true
15892			},
15893			keyboard: {
15894				left: true, // previous
15895				right: true, // next
15896				up: true, // previous
15897				down: true, // next
15898				esc: true, // close
15899				shift_enter: true // fullscreen
15900			},
15901			show: {
15902				effect: true,
15903				speed: 300,
15904				title: true
15905			},
15906			hide: {
15907				effect: true,
15908				speed: 300
15909			},
15910			caption: {
15911				start: true,
15912				show: 'mouseenter',
15913				hide: 'mouseleave'
15914			},
15915			social: {
15916				start: true,
15917				show: 'mouseenter',
15918				hide: 'mouseleave',
15919				buttons: false
15920			},
15921			styles: {
15922				pageOffsetX: 0,
15923				pageOffsetY: 0,
15924				nextOffsetX: 45,
15925				nextOffsetY: 0,
15926				nextOpacity: 1,
15927				nextScale: 1,
15928				prevOffsetX: 45,
15929				prevOffsetY: 0,
15930				prevOpacity: 1,
15931				prevScale: 1
15932			},
15933			thumbnails: {
15934				maxWidth: 120,
15935				maxHeight: 80,
15936				normalOpacity: 1,
15937				activeOpacity: .6
15938			},
15939			effects: {
15940				reposition: true,
15941				repositionSpeed: 200,
15942				switchSpeed: 500,
15943				loadedFadeSpeed: 180,
15944				fadeSpeed: 200
15945			},
15946			slideshow: {
15947				pauseTime: 5000,
15948				pauseOnHover: false,
15949				startPaused: true
15950			},
15951			text: {
15952				close: "Press Esc to close",
15953				enterFullscreen: "Enter Fullscreen (Shift+Enter)",
15954				exitFullscreen: "Exit Fullscreen (Shift+Enter)",
15955				slideShow: "Slideshow",
15956				next: "Next",
15957				previous: "Previous"
15958			},
15959			errors: {
15960				loadImage: "An error occurred when trying to load photo.",
15961				loadContents: "An error occurred when trying to load contents.",
15962				missingPlugin: "The content your are attempting to view requires the <a href='{pluginspage}' target='_blank'>{type} plugin<\/a>."
15963			},
15964			ajaxSetup: {
15965				url: '',
15966				beforeSend: function(jqXHR, settings) {},
15967				cache: false,
15968				complete: function(jqXHR, textStatus) {},
15969				crossDomain: false,
15970				error: function(jqXHR, textStatus, errorThrown) {},
15971				success: function(data, textStatus, jqXHR) {},
15972				global: true,
15973				ifModified: false,
15974				username: null,
15975				password: null,
15976				type: 'GET'
15977			},
15978			callback: {}
15979		}, opt);
15980
15981		var instant = ($.isArray(items) || typeof items == 'string') ? true : false;
15982
15983		items = $.isArray(items) ? items : new Array();
15984
15985		if (typeof args[0] == 'string') items[0] = args[0];
15986
15987		if (version_compare($.fn.jquery, '1.8', '>=')) {
15988			var iLB = new iLightBox($(this), options, items, instant);
15989			return {
15990				close: function() {
15991					iLB.closeAction();
15992				},
15993				fullscreen: function() {
15994					iLB.fullScreenAction();
15995				},
15996				moveNext: function() {
15997					iLB.moveTo('next');
15998				},
15999				movePrev: function() {
16000					iLB.moveTo('prev');
16001				},
16002				goTo: function(index) {
16003					iLB.goTo(index);
16004				},
16005				refresh: function() {
16006					iLB.refresh();
16007				},
16008				reposition: function() {
16009					(arguments.length > 0) ? iLB.repositionPhoto(true): iLB.repositionPhoto();
16010				},
16011				setOption: function(options) {
16012					iLB.setOption(options);
16013				},
16014				destroy: function() {
16015					iLB.closeAction();
16016					iLB.dispatchItemsEvents();
16017				}
16018			};
16019		} else {
16020			throw "The jQuery version that was loaded is too old. iLightBox requires jQuery 1.8+";
16021		}
16022
16023	};
16024
16025
16026	$.iLightBox = function() {
16027		return $.fn.iLightBox(arguments[0], arguments[1]);
16028	};
16029
16030	function getScrollXY() {
16031		var scrOfX = 0,
16032			scrOfY = 0;
16033		if (typeof(window.pageYOffset) == 'number') {
16034			//Netscape compliant
16035			scrOfY = window.pageYOffset;
16036			scrOfX = window.pageXOffset;
16037		} else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
16038			//DOM compliant
16039			scrOfY = document.body.scrollTop;
16040			scrOfX = document.body.scrollLeft;
16041		} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
16042			//IE6 standards compliant mode
16043			scrOfY = document.documentElement.scrollTop;
16044			scrOfX = document.documentElement.scrollLeft;
16045		}
16046		return {
16047			x: scrOfX,
16048			y: scrOfY
16049		};
16050	}
16051
16052	(function() {
16053		// add new event shortcuts
16054		$.each(("touchstart touchmove touchend " +
16055			"tap taphold " +
16056			"swipe swipeleft swiperight " +
16057			"scrollstart scrollstop").split(" "), function(i, name) {
16058
16059			$.fn[name] = function(fn) {
16060				return fn ? this.bind(name, fn) : this.trigger(name);
16061			};
16062
16063			// jQuery < 1.8
16064			// if ($.attrFn) {
16065			// 	$.attrFn[name] = true;
16066			// }
16067		});
16068
16069		var tapSettings = {
16070			startEvent: 'touchstart.iTap',
16071			endEvent: 'touchend.iTap'
16072		};
16073
16074		// tap Event:
16075		$.event.special.itap = {
16076			setup: function() {
16077
16078				var self = this,
16079					$self = $(this),
16080					start, stop;
16081
16082				$self.bind(tapSettings.startEvent, function(event) {
16083					start = getScrollXY();
16084
16085					$self.one(tapSettings.endEvent, function(event) {
16086						stop = getScrollXY();
16087
16088						var orgEvent = event || window.event;
16089						event = $.event.fix(orgEvent);
16090						event.type = "itap";
16091
16092						if ((start && stop) && (start.x == stop.x && start.y == stop.y))($.event.dispatch || $.event.handle).call(self, event);
16093
16094						start = stop = undefined;
16095					});
16096				});
16097			},
16098
16099			teardown: function() {
16100				$(this).unbind(tapSettings.startEvent);
16101			}
16102		};
16103	}());
16104
16105
16106	//Fullscreen API
16107	(function() {
16108		fullScreenApi = {
16109				supportsFullScreen: false,
16110				isFullScreen: function() {
16111					return false;
16112				},
16113				requestFullScreen: function() {},
16114				cancelFullScreen: function() {},
16115				fullScreenEventName: '',
16116				prefix: ''
16117			},
16118			browserPrefixes = 'webkit moz o ms khtml'.split(' ');
16119
16120		// check for native support
16121		if (typeof document.cancelFullScreen != 'undefined') {
16122			fullScreenApi.supportsFullScreen = true;
16123		} else {
16124			// check for fullscreen support by vendor prefix
16125			for (var i = 0, il = browserPrefixes.length; i < il; i++) {
16126				fullScreenApi.prefix = browserPrefixes[i];
16127
16128				if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] != 'undefined') {
16129					fullScreenApi.supportsFullScreen = true;
16130
16131					break;
16132				}
16133			}
16134		}
16135
16136		// update methods to do something useful
16137		if (fullScreenApi.supportsFullScreen) {
16138			fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
16139
16140			fullScreenApi.isFullScreen = function() {
16141				switch (this.prefix) {
16142					case '':
16143						return document.fullScreen;
16144					case 'webkit':
16145						return document.webkitIsFullScreen;
16146					default:
16147						return document[this.prefix + 'FullScreen'];
16148				}
16149			}
16150			fullScreenApi.requestFullScreen = function(el) {
16151				return (this.prefix === '') ? el.requestFullScreen() : el[this.prefix + 'RequestFullScreen']();
16152			}
16153			fullScreenApi.cancelFullScreen = function(el) {
16154				return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + 'CancelFullScreen']();
16155			}
16156		}
16157	}());
16158
16159	// Browser detect
16160	(function() {
16161		function uaMatch(ua) {
16162			ua = ua.toLowerCase();
16163
16164			var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
16165				/(webkit)[ \/]([\w.]+)/.exec(ua) ||
16166				/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
16167				/(msie) ([\w.]+)/.exec(ua) ||
16168				ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
16169
16170			return {
16171				browser: match[1] || "",
16172				version: match[2] || "0"
16173			};
16174		}
16175
16176		var matched = uaMatch(navigator.userAgent);
16177		browser = {};
16178
16179		if (matched.browser) {
16180			browser[matched.browser] = true;
16181			browser.version = matched.version;
16182		}
16183
16184		// Chrome is Webkit, but Webkit is also Safari.
16185		if (browser.chrome) {
16186			browser.webkit = true;
16187		} else if (browser.webkit) {
16188			browser.safari = true;
16189		}
16190	}());
16191
16192	// Feature detects
16193	(function() {
16194		var prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
16195		var el = document.createElement('div');
16196
16197		function testProp(prop) {
16198			for (var p = 0, pl = prefixes.length; p < pl; p++) {
16199				var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop;
16200				if (el.style[prefixedProp] !== undefined) {
16201					return prefixedProp;
16202				}
16203			}
16204		}
16205
16206		// Global support indicators
16207		transform = testProp('transform') || '';
16208		gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : '';
16209	}());
16210
16211
16212	/*
16213		PluginDetect v0.7.9
16214		www.pinlady.net/PluginDetect/license/
16215		[ getVersion onWindowLoaded BetterIE ]
16216		[ Flash QuickTime Shockwave ]
16217	*/
16218	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;
16218d++){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);
16218d.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)}
16218c.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;
16218if(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();
16219
16220	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)};
16221
16222
16223	/*
16224		jQuery hashchange event v1.3
16225		https://github.com/cowboy/jquery-hashchange
16226		Copyright (c) 2010 "Cowboy" Ben Alman
16227		Dual licensed under the MIT and GPL licenses.
16228	*/
16229	(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=
16230	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||
16231	"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;
16231a!==d&&(b.title=k.title,b.open(),e&&b.write('<script>document.domain="'+e+'"\x3c/script>'),b.close(),c.location.hash=a)}}();return h}()})();
16232
16233	if (!Array.prototype.filter) {
16234		Array.prototype.filter = function(fun /*, thisp */ ) {
16235			"use strict";
16236
16237			if (this == null)
16238				throw new TypeError();
16239
16240			var t = Object(this);
16241			var len = t.length >>> 0;
16242			if (typeof fun != "function")
16243				throw new TypeError();
16244
16245			var res = [];
16246			var thisp = arguments[1];
16247			for (var i = 0; i < len; i++) {
16248				if (i in t) {
16249					var val = t[i]; // in case fun mutates this
16250					if (fun.call(thisp, val, i, t))
16251						res.push(val);
16252				}
16253			}
16254
16255			return res;
16256		};
16257	}
16258
16259	if (!Array.prototype.indexOf) {
16260		Array.prototype.indexOf = function(searchElement, fromIndex) {
16261			var k;
16262
16263			if (this == null) {
16264				throw new TypeError('"this" is null or not defined');
16265			}
16266
16267			var O = Object(this);
16268
16269			var len = O.length >>> 0;
16270
16271			if (len === 0) {
16272				return -1;
16273			}
16274
16275			var n = +fromIndex || 0;
16276
16277			if (abs(n) === Infinity) {
16278				n = 0;
16279			}
16280
16281			if (n >= len) {
16282				return -1;
16283			}
16284
16285			k = max(n >= 0 ? n : len - abs(n), 0);
16286
16287			while (k < len) {
16288				var kValue;
16289				if (k in O && O[k] === searchElement) {
16290					return k;
16291				}
16292				k++;
16293			}
16294			return -1;
16295		};
16296	}
16297
16298	if (!Array.prototype.lastIndexOf) {
16299		Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/ ) {
16300			"use strict";
16301
16302			if (this == null)
16303				throw new TypeError();
16304
16305			var t = Object(this);
16306			var len = t.length >>> 0;
16307			if (len === 0)
16308				return -1;
16309
16310			var n = len;
16311			if (arguments.length > 1) {
16312				n = Number(arguments[1]);
16313				if (n != n)
16314					n = 0;
16315				else if (n != 0 && n != (1 / 0) && n != -(1 / 0))
16316					n = (n > 0 || -1) * floor(abs(n));
16317			}
16318
16319			var k = n >= 0 ? min(n, len - 1) : len - abs(n);
16320
16321			for (; k >= 0; k--) {
16322				if (k in t && t[k] === searchElement)
16323					return k;
16324			}
16325			return -1;
16326		};
16327	}
16328})(jQuery, this);
16329
16330/**
16331 * Owl carousel
vendor: 61,882 bytes, lines 16332-18683
16332 * @version 2.0.0-beta.3
16333 * @author Bartosz Wojciechowski
16334 * @license The MIT License (MIT)
16335 * @todo Lazy Load Icon
16336 * @todo prevent animationend bubling
16337 * @todo itemsScaleUp
16338 * @todo Test Zepto
16339 * @todo stagePadding calculate wrong active classes
16340 */
16341;(function($, window, document, undefined) {
16342
16343	/**
16344	 * Creates a carousel.
16345	 * @class The Owl Carousel.
16346	 * @public
16347	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
16348	 * @param {Object} [options] - The options
16349	 */
16350	function Owl(element, options) {
16351
16352		/**
16353		 * Current settings for the carousel.
16354		 * @public
16355		 */
16356		this.settings = null;
16357
16358		/**
16359		 * Current options set by the caller including defaults.
16360		 * @public
16361		 */
16362		this.options = $.extend({}, Owl.Defaults, options);
16363
16364		/**
16365		 * Plugin element.
16366		 * @public
16367		 */
16368		this.$element = $(element);
16369
16370		/**
16371		 * Proxied event handlers.
16372		 * @protected
16373		 */
16374		this._handlers = {};
16375
16376		/**
16377		 * References to the running plugins of this carousel.
16378		 * @protected
16379		 */
16380		this._plugins = {};
16381
16382		/**
16383		 * Currently suppressed events to prevent them from beeing retriggered.
16384		 * @protected
16385		 */
16386		this._supress = {};
16387
16388		/**
16389		 * Absolute current position.
16390		 * @protected
16391		 */
16392		this._current = null;
16393
16394		/**
16395		 * Animation speed in milliseconds.
16396		 * @protected
16397		 */
16398		this._speed = null;
16399
16400		/**
16401		 * Coordinates of all items in pixel.
16402		 * @todo The name of this member is missleading.
16403		 * @protected
16404		 */
16405		this._coordinates = [];
16406
16407		/**
16408		 * Current breakpoint.
16409		 * @todo Real media queries would be nice.
16410		 * @protected
16411		 */
16412		this._breakpoint = null;
16413
16414		/**
16415		 * Current width of the plugin element.
16416		 */
16417		this._width = null;
16418
16419		/**
16420		 * All real items.
16421		 * @protected
16422		 */
16423		this._items = [];
16424
16425		/**
16426		 * All cloned items.
16427		 * @protected
16428		 */
16429		this._clones = [];
16430
16431		/**
16432		 * Merge values of all items.
16433		 * @todo Maybe this could be part of a plugin.
16434		 * @protected
16435		 */
16436		this._mergers = [];
16437
16438		/**
16439		 * Widths of all items.
16440		 */
16441		this._widths = [];
16442
16443		/**
16444		 * Invalidated parts within the update process.
16445		 * @protected
16446		 */
16447		this._invalidated = {};
16448
16449		/**
16450		 * Ordered list of workers for the update process.
16451		 * @protected
16452		 */
16453		this._pipe = [];
16454
16455		/**
16456		 * Current state information for the drag operation.
16457		 * @todo #261
16458		 * @protected
16459		 */
16460		this._drag = {
16461			time: null,
16462			target: null,
16463			pointer: null,
16464			stage: {
16465				start: null,
16466				current: null
16467			},
16468			direction: null
16469		};
16470
16471		/**
16472		 * Current state information and their tags.
16473		 * @type {Object}
16474		 * @protected
16475		 */
16476		this._states = {
16477			current: {},
16478			tags: {
16479				'initializing': [ 'busy' ],
16480				'animating': [ 'busy' ],
16481				'dragging': [ 'interacting' ]
16482			}
16483		};
16484
16485		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
16486			this._handlers[handler] = $.proxy(this[handler], this);
16487		}, this));
16488
16489		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
16490			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
16491				= new plugin(this);
16492		}, this));
16493
16494		$.each(Owl.Workers, $.proxy(function(priority, worker) {
16495			this._pipe.push({
16496				'filter': worker.filter,
16497				'run': $.proxy(worker.run, this)
16498			});
16499		}, this));
16500
16501		this.setup();
16502		this.initialize();
16503	}
16504
16505	/**
16506	 * Default options for the carousel.
16507	 * @public
16508	 */
16509	Owl.Defaults = {
16510		items: 3,
16511		loop: false,
16512		center: false,
16513		rewind: false,
16514
16515		mouseDrag: true,
16516		touchDrag: true,
16517		pullDrag: true,
16518		freeDrag: false,
16519
16520		margin: 0,
16521		stagePadding: 0,
16522
16523		merge: false,
16524		mergeFit: true,
16525		autoWidth: false,
16526
16527		startPosition: 0,
16528		rtl: false,
16529
16530		smartSpeed: 250,
16531		fluidSpeed: false,
16532		dragEndSpeed: false,
16533
16534		responsive: {},
16535		responsiveRefreshRate: 200,
16536		responsiveBaseElement: window,
16537
16538		fallbackEasing: 'swing',
16539
16540		info: false,
16541
16542		nestedItemSelector: false,
16543		itemElement: 'div',
16544		stageElement: 'div',
16545
16546		refreshClass: 'owl-refresh',
16547		loadedClass: 'owl-loaded',
16548		loadingClass: 'owl-loading',
16549		rtlClass: 'owl-rtl',
16550		responsiveClass: 'owl-responsive',
16551		dragClass: 'owl-drag',
16552		itemClass: 'owl-item',
16553		stageClass: 'owl-stage',
16554		stageOuterClass: 'owl-stage-outer',
16555		grabClass: 'owl-grab'
16556	};
16557
16558	/**
16559	 * Enumeration for width.
16560	 * @public
16561	 * @readonly
16562	 * @enum {String}
16563	 */
16564	Owl.Width = {
16565		Default: 'default',
16566		Inner: 'inner',
16567		Outer: 'outer'
16568	};
16569
16570	/**
16571	 * Enumeration for types.
16572	 * @public
16573	 * @readonly
16574	 * @enum {String}
16575	 */
16576	Owl.Type = {
16577		Event: 'event',
16578		State: 'state'
16579	};
16580
16581	/**
16582	 * Contains all registered plugins.
16583	 * @public
16584	 */
16585	Owl.Plugins = {};
16586
16587	/**
16588	 * List of workers involved in the update process.
16589	 */
16590	Owl.Workers = [ {
16591		filter: [ 'width', 'settings' ],
16592		run: function() {
16593			this._width = (this.$element.closest('.px-gutter').length) ? 12 * Math.ceil(this.$element.width() / 12) : this.$element.width();
16594			//this._width = (UNCODE.isMobile) ? this.$element.width() : 12 * Math.ceil(this.$element.width() / 12);
16595		}
16596	}, {
16597		filter: [ 'width', 'items', 'settings' ],
16598		run: function(cache) {
16599			cache.current = this._items && this._items[this.relative(this._current)];
16600		}
16601	}, {
16602		filter: [ 'items', 'settings' ],
16603		run: function() {
16604			this.$stage.children('.cloned').remove();
16605		}
16606	}, {
16607		filter: [ 'width', 'items', 'settings' ],
16608		run: function(cache) {
16609			var margin = this.settings.margin || '',
16610				grid = !this.settings.autoWidth,
16611				rtl = this.settings.rtl,
16612				css = {
16613					'width': 'auto',
16614					'margin-left': rtl ? margin : '',
16615					'margin-right': rtl ? '' : margin
16616				};
16617
16618			!grid && this.$stage.children().css(css);
16619
16620			cache.css = css;
16621		}
16622	}, {
16623		filter: [ 'width', 'items', 'settings' ],
16624		run: function(cache) {
16625			//UNCODE edit to fix Chrome stage padding issue
16626			var width = Math.round((this.width() / this.settings.items).toFixed(3) - this.settings.margin),
16627				merge = null,
16628				iterator = this._items.length,
16629				grid = !this.settings.autoWidth,
16630				widths = [];
16631
16632			cache.items = {
16633				merge: false,
16634				width: width
16635			};
16636
16637			while (iterator--) {
16638				merge = this._mergers[iterator];
16639				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
16640
16641				cache.items.merge = merge > 1 || cache.items.merge;
16642
16643				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
16644			}
16645
16646			this._widths = widths;
16647		}
16648	}, {
16649		filter: [ 'items', 'settings' ],
16650		run: function() {
16651			var clones = [],
16652				items = this._items,
16653				settings = this.settings,
16654				view = Math.max(settings.items * 2, 4),
16655				size = Math.ceil(items.length / 2) * 2,
16656				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
16657				append = '',
16658				prepend = '';
16659
16660			repeat /= 2;
16661
16662			while (repeat--) {
16663				clones.push(this.normalize(clones.length / 2, true));
16664				append = append + items[clones[clones.length - 1]][0].outerHTML;
16665				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
16666				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
16667			}
16668
16669			this._clones = clones;
16670
16671			// var appendVideo = $(append).find('.uncode-video-container');
16672			// if (appendVideo.length) {
16673			// 	appendVideo.attr('data-id', Math.round(Math.random() * 100000));
16674			// }
16675			// var prependVideo = $(prepend).find('.uncode-video-container');
16676			// if (prependVideo.length) {
16677			// 	prependVideo.attr('data-id', Math.round(Math.random() * 100000));
16678			// }
16679			$(append).addClass('cloned').appendTo(this.$stage);
16680			$(prepend).addClass('cloned').prependTo(this.$stage);
16681		}
16682	}, {
16683		filter: [ 'width', 'items', 'settings' ],
16684		run: function() {
16685			var rtl = this.settings.rtl ? 1 : -1,
16686				size = this._clones.length + this._items.length,
16687				iterator = -1,
16688				previous = 0,
16689				current = 0,
16690				coordinates = [];
16691
16692			while (++iterator < size) {
16693				previous = coordinates[iterator - 1] || 0;
16694				current = this._widths[this.relative(iterator)] + this.settings.margin;
16695				coordinates.push(previous + current * rtl);
16696			}
16697
16698			this._coordinates = coordinates;
16699		}
16700	}, {
16701		filter: [ 'width', 'items', 'settings' ],
16702		run: function() {
16703			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
16704				padding = stagePadding,
16705				coordinates = this._coordinates,
16706				css = {
16707					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
16708					'padding-left': padding || '',
16709					'padding-right': padding || ''
16710				};
16711
16712			this.$stage.css(css);
16713		}
16714	}, {
16715		filter: [ 'width', 'items', 'settings' ],
16716		run: function(cache) {
16717			var iterator = this._coordinates.length,
16718				grid = !this.settings.autoWidth,
16719				items = this.$stage.children();
16720
16721			if (grid && cache.items.merge) {
16722				while (iterator--) {
16723					cache.css.width = this._widths[this.relative(iterator)];
16724					items.eq(iterator).css(cache.css);
16725				}
16726			} else if (grid) {
16727				cache.css.width = cache.items.width;
16728				items.css(cache.css);
16729			}
16730		}
16731	}, {
16732		filter: [ 'items' ],
16733		run: function() {
16734			this._coordinates.length < 1 && this.$stage.removeAttr('style');
16735		}
16736	}, {
16737		filter: [ 'width', 'items', 'settings' ],
16738		run: function(cache) {
16739			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
16740			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
16741			this.reset(cache.current);
16742		}
16743	}, {
16744		filter: [ 'position' ],
16745		run: function() {
16746			this.animate(this.coordinates(this._current));
16747		}
16748	}, {
16749		filter: [ 'width', 'position', 'items', 'settings' ],
16750		run: function() {
16751			var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200,
16752				rtl = this.settings.rtl ? 1 : -1,
16753				padding = this.settings.stagePadding * 2,
16754				begin = this.coordinates(this.current()) + padding,
16755				end = begin + this.width() * rtl,
16756				inner, outer, matches = [], i, n;
16757
16758			for (i = 0, n = this._coordinates.length; i < n; i++) {
16759				inner = this._coordinates[i - 1] || 0;
16760				outer = Math.abs(this._coordinates[i]) + padding * rtl;
16761
16762				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
16763					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
16764					matches.push(i);
16765				}
16766			}
16767
16768			this.$stage.children('.active').removeClass('active');
16769			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
16770
16771			if (this.settings.center) {
16772				this.$stage.children('.center').removeClass('center');
16773				this.$stage.children().eq(this.current()).addClass('center');
16774			}
16775		}
16776	} ];
16777
16778	/**
16779	 * Initializes the carousel.
16780	 * @protected
16781	 */
16782	Owl.prototype.initialize = function() {
16783		this.enter('initializing');
16784		this.trigger('initialize');
16785
16786		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
16787
16788		if (this.settings.autoWidth && !this.is('pre-loading')) {
16789			var imgs, nestedSelector, width;
16790			imgs = this.$element.find('img');
16791			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
16792			width = this.$element.children(nestedSelector).width();
16793
16794			if (imgs.length && width <= 0) {
16795				this.preloadAutoWidthImages(imgs);
16796			}
16797		}
16798
16799		this.$element.addClass(this.options.loadingClass);
16800
16801		// create stage
16802		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
16803			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
16804
16805		// append stage
16806		this.$element.append(this.$stage.parent());
16807
16808		// append content
16809		this.replace(this.$element.children().not(this.$stage.parent()));
16810
16811		// check visibility
16812		if (this.$element.is(':visible')) {
16813			// update view
16814			this.refresh();
16815		} else {
16816			// invalidate width
16817			this.invalidate('width');
16818		}
16819
16820		this.$element
16821			.removeClass(this.options.loadingClass)
16822			.addClass(this.options.loadedClass);
16823
16824		// register event handlers
16825		this.registerEventHandlers();
16826
16827		this.leave('initializing');
16828		this.trigger('initialized');
16829	};
16830
16831	/**
16832	 * Setups the current settings.
16833	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
16834	 * @todo Support for media queries by using `matchMedia` would be nice.
16835	 * @public
16836	 */
16837	Owl.prototype.setup = function() {
16838		var viewport = this.viewport(),
16839			overwrites = this.options.responsive,
16840			match = -1,
16841			settings = null;
16842
16843		if (!overwrites) {
16844			settings = $.extend({}, this.options);
16845		} else {
16846			$.each(overwrites, function(breakpoint) {
16847				if (breakpoint <= viewport && breakpoint > match) {
16848					match = Number(breakpoint);
16849				}
16850			});
16851
16852			settings = $.extend({}, this.options, overwrites[match]);
16853			delete settings.responsive;
16854
16855			// responsive class
16856			if (settings.responsiveClass) {
16857				this.$element.attr('class',
16858					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
16859				);
16860			}
16861		}
16862
16863		if (this.settings === null || this._breakpoint !== match) {
16864			this.trigger('change', { property: { name: 'settings', value: settings } });
16865			this._breakpoint = match;
16866			this.settings = settings;
16867			this.invalidate('settings');
16868			this.trigger('changed', { property: { name: 'settings', value: this.settings } });
16869		}
16870	};
16871
16872	/**
16873	 * Updates option logic if necessery.
16874	 * @protected
16875	 */
16876	Owl.prototype.optionsLogic = function() {
16877		if (this.settings.autoWidth) {
16878			this.settings.stagePadding = false;
16879			this.settings.merge = false;
16880		}
16881	};
16882
16883	/**
16884	 * Prepares an item before add.
16885	 * @todo Rename event parameter `content` to `item`.
16886	 * @protected
16887	 * @returns {jQuery|HTMLElement} - The item container.
16888	 */
16889	Owl.prototype.prepare = function(item, index) {
16890		var event = this.trigger('prepare', { content: item });
16891		if (!event.data) {
16892			event.data = $('<' + this.settings.itemElement + '/>')
16893				.addClass(this.options.itemClass).attr('data-index', index + 1).append(item)
16894		}
16895
16896		this.trigger('prepared', { content: event.data });
16897
16898		return event.data;
16899	};
16900
16901	/**
16902	 * Updates the view.
16903	 * @public
16904	 */
16905	Owl.prototype.update = function() {
16906		var i = 0,
16907			n = this._pipe.length,
16908			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
16909			cache = {};
16910
16911		while (i < n) {
16912			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
16913				this._pipe[i].run(cache);
16914			}
16915			i++;
16916		}
16917
16918		this._invalidated = {};
16919
16920		!this.is('valid') && this.enter('valid');
16921	};
16922
16923	/**
16924	 * Gets the width of the view.
16925	 * @public
16926	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
16927	 * @returns {Number} - The width of the view in pixel.
16928	 */
16929	Owl.prototype.width = function(dimension) {
16930		dimension = dimension || Owl.Width.Default;
16931		var stagePadding = (this._width < 480 && this.settings.stagePadding > 0) ? 41 : (this._width * this.settings.stagePadding) / 200;
16932		switch (dimension) {
16933			case Owl.Width.Inner:
16934			case Owl.Width.Outer:
16935				return this._width;
16936			default:
16937				return this._width - stagePadding * 2 + this.settings.margin;
16938		}
16939	};
16940
16941	/**
16942	 * Refreshes the carousel primarily for adaptive purposes.
16943	 * @public
16944	 */
16945	Owl.prototype.refresh = function() {
16946		this.enter('refreshing');
16947		this.trigger('refresh');
16948
16949		this.setup();
16950
16951		this.optionsLogic();
16952
16953		this.$element.addClass(this.options.refreshClass);
16954
16955		this.update();
16956
16957		this.$element.removeClass(this.options.refreshClass);
16958
16959		this.leave('refreshing');
16960		this.trigger('refreshed');
16961	};
16962
16963	/**
16964	 * Checks window `resize` event.
16965	 * @protected
16966	 */
16967	Owl.prototype.onThrottledResize = function() {
16968		window.clearTimeout(this.resizeTimer);
16969		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
16970	};
16971
16972	/**
16973	 * Checks window `resize` event.
16974	 * @protected
16975	 */
16976	Owl.prototype.onResize = function() {
16977		if (!this._items.length) {
16978			return false;
16979		}
16980
16981		if (this._width === this.$element.width()) {
16982			return false;
16983		}
16984
16985		if (!this.$element.is(':visible')) {
16986			return false;
16987		}
16988
16989		this.enter('resizing');
16990
16991		if (this.trigger('resize').isDefaultPrevented()) {
16992			this.leave('resizing');
16993			return false;
16994		}
16995
16996		this.invalidate('width');
16997
16998		this.refresh();
16999
17000		this.leave('resizing');
17001		this.trigger('resized');
17002	};
17003
17004	/**
17005	 * Registers event handlers.
17006	 * @todo Check `msPointerEnabled`
17007	 * @todo #261
17008	 * @protected
17009	 */
17010	Owl.prototype.registerEventHandlers = function() {
17011		if ($.support.transition) {
17012			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
17013		}
17014
17015		if (this.settings.responsive !== false) {
17016			this.on(window, 'resize', this._handlers.onThrottledResize);
17017		}
17018
17019		if (this.settings.mouseDrag) {
17020			this.$element.addClass(this.options.dragClass);
17021			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
17022			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
17023		}
17024
17025		if (this.settings.touchDrag){
17026			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
17027			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
17028		}
17029	};
17030
17031	/**
17032	 * Handles `touchstart` and `mousedown` events.
17033	 * @todo Horizontal swipe threshold as option
17034	 * @todo #261
17035	 * @protected
17036	 * @param {Event} event - The event arguments.
17037	 */
17038	Owl.prototype.onDragStart = function(event) {
17039		var stage = null;
17040
17041		if (event.which === 3) {
17042			return;
17043		}
17044
17045		if ($.support.transform) {
17046			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
17047			stage = {
17048				x: stage[stage.length === 16 ? 12 : 4],
17049				y: stage[stage.length === 16 ? 13 : 5]
17050			};
17051		} else {
17052			stage = this.$stage.position();
17053			stage = {
17054				x: this.settings.rtl ?
17055					stage.left + this.$stage.width() - this.width() + this.settings.margin :
17056					stage.left,
17057				y: stage.top
17058			};
17059		}
17060
17061		if (this.is('animating')) {
17062			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
17063			this.invalidate('position');
17064		}
17065
17066		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
17067
17068		this.speed(0);
17069
17070		this._drag.time = new Date().getTime();
17071		this._drag.target = $(event.target);
17072		this._drag.stage.start = stage;
17073		this._drag.stage.current = stage;
17074		this._drag.pointer = this.pointer(event);
17075
17076		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
17077
17078		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
17079			var delta = this.difference(this._drag.pointer, this.pointer(event));
17080
17081			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
17082
17083			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
17084				return;
17085			}
17086
17087			event.preventDefault();
17088
17089			this.enter('dragging');
17090			this.trigger('drag');
17091		}, this));
17092	};
17093
17094	/**
17095	 * Handles the `touchmove` and `mousemove` events.
17096	 * @todo #261
17097	 * @protected
17098	 * @param {Event} event - The event arguments.
17099	 */
17100	Owl.prototype.onDragMove = function(event) {
17101		var minimum = null,
17102			maximum = null,
17103			pull = null,
17104			delta = this.difference(this._drag.pointer, this.pointer(event)),
17105			stage = this.difference(this._drag.stage.start, delta);
17106
17107		if (!this.is('dragging')) {
17108			return;
17109		}
17110
17111		event.preventDefault();
17112
17113		if (this.settings.loop) {
17114			minimum = this.coordinates(this.minimum());
17115			maximum = this.coordinates(this.maximum() + 1) - minimum;
17116			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
17117		} else {
17118			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
17119			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
17120			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
17121			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
17122		}
17123
17124		this._drag.stage.current = stage;
17125
17126		this.animate(stage.x);
17127	};
17128
17129	/**
17130	 * Handles the `touchend` and `mouseup` events.
17131	 * @todo #261
17132	 * @todo Threshold for click event
17133	 * @protected
17134	 * @param {Event} event - The event arguments.
17135	 */
17136	Owl.prototype.onDragEnd = function(event) {
17137		var delta = this.difference(this._drag.pointer, this.pointer(event)),
17138			stage = this._drag.stage.current,
17139			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
17140
17141		$(document).off('.owl.core');
17142
17143		this.$element.removeClass(this.options.grabClass);
17144
17145		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
17146			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
17147			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
17148			this.invalidate('position');
17149			this.update();
17150
17151			this._drag.direction = direction;
17152
17153			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
17154				this._drag.target.one('click.owl.core', function() { return false; });
17155			}
17156		}
17157
17158		if (!this.is('dragging')) {
17159			return;
17160		}
17161
17162		this.leave('dragging');
17163		this.trigger('dragged');
17164	};
17165
17166	/**
17167	 * Gets absolute position of the closest item for a coordinate.
17168	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
17169	 * @protected
17170	 * @param {Number} coordinate - The coordinate in pixel.
17171	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
17172	 * @return {Number} - The absolute position of the closest item.
17173	 */
17174	Owl.prototype.closest = function(coordinate, direction) {
17175		var position = -1,
17176			pull = 30,
17177			width = this.width(),
17178			coordinates = this.coordinates();
17179
17180		if (!this.settings.freeDrag) {
17181			// check closest item
17182			$.each(coordinates, $.proxy(function(index, value) {
17183				if (coordinate > value - pull && coordinate < value + pull) {
17184					position = index;
17185				} else if (this.op(coordinate, '<', value)
17186					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
17187					position = direction === 'left' ? index + 1 : index;
17188				}
17189				return position === -1;
17190			}, this));
17191		}
17192
17193		if (!this.settings.loop) {
17194			// non loop boundries
17195			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
17196				position = coordinate = this.minimum();
17197			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
17198				position = coordinate = this.maximum();
17199			}
17200		}
17201
17202		return position;
17203	};
17204
17205	/**
17206	 * Animates the stage.
17207	 * @todo #270
17208	 * @public
17209	 * @param {Number} coordinate - The coordinate in pixels.
17210	 */
17211	Owl.prototype.animate = function(coordinate) {
17212		var animate = this.speed() > 0;
17213
17214		this.is('animating') && this.onTransitionEnd();
17215
17216		if (animate) {
17217			this.enter('animating');
17218			this.trigger('translate');
17219		}
17220
17221		if ($.support.transform3d && $.support.transition) {
17222			this.$stage.css({
17223				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
17224				transition: (this.speed() / 1000) + 's'
17225			});
17226		} else if (animate) {
17227			this.$stage.animate({
17228				left: coordinate + 'px'
17229			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
17230		} else {
17231			this.$stage.css({
17232				left: coordinate + 'px'
17233			});
17234		}
17235	};
17236
17237	/**
17238	 * Checks whether the carousel is in a specific state or not.
17239	 * @param {String} state - The state to check.
17240	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
17241	 */
17242	Owl.prototype.is = function(state) {
17243		return this._states.current[state] && this._states.current[state] > 0;
17244	};
17245
17246	/**
17247	 * Sets the absolute position of the current item.
17248	 * @public
17249	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
17250	 * @returns {Number} - The absolute position of the current item.
17251	 */
17252	Owl.prototype.current = function(position) {
17253		if (position === undefined) {
17254			return this._current;
17255		}
17256
17257		if (this._items.length === 0) {
17258			return undefined;
17259		}
17260
17261		position = this.normalize(position);
17262
17263		if (this._current !== position) {
17264			var event = this.trigger('change', { property: { name: 'position', value: position } });
17265
17266			if (event.data !== undefined) {
17267				position = this.normalize(event.data);
17268			}
17269
17270			this._current = position;
17271
17272			this.invalidate('position');
17273
17274			this.trigger('changed', { property: { name: 'position', value: this._current } });
17275		}
17276
17277		return this._current;
17278	};
17279
17280	/**
17281	 * Invalidates the given part of the update routine.
17282	 * @param {String} [part] - The part to invalidate.
17283	 * @returns {Array.<String>} - The invalidated parts.
17284	 */
17285	Owl.prototype.invalidate = function(part) {
17286		if ($.type(part) === 'string') {
17287			this._invalidated[part] = true;
17288			this.is('valid') && this.leave('valid');
17289		}
17290		return $.map(this._invalidated, function(v, i) { return i });
17291	};
17292
17293	/**
17294	 * Resets the absolute position of the current item.
17295	 * @public
17296	 * @param {Number} position - The absolute position of the new item.
17297	 */
17298	Owl.prototype.reset = function(position) {
17299		position = this.normalize(position);
17300
17301		if (position === undefined) {
17302			return;
17303		}
17304
17305		this._speed = 0;
17306		this._current = position;
17307
17308		this.suppress([ 'translate', 'translated' ]);
17309
17310		this.animate(this.coordinates(position));
17311
17312		this.release([ 'translate', 'translated' ]);
17313	};
17314
17315	/**
17316	 * Normalizes an absolute or a relative position of an item.
17317	 * @public
17318	 * @param {Number} position - The absolute or relative position to normalize.
17319	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
17320	 * @returns {Number} - The normalized position.
17321	 */
17322	Owl.prototype.normalize = function(position, relative) {
17323		var n = this._items.length,
17324			m = relative ? 0 : this._clones.length;
17325
17326		if (!$.isNumeric(position) || n < 1) {
17327			position = undefined;
17328		} else if (position < 0 || position >= n + m) {
17329			position = ((position - m / 2) % n + n) % n + m / 2;
17330		}
17331
17332		return position;
17333	};
17334
17335	/**
17336	 * Converts an absolute position of an item into a relative one.
17337	 * @public
17338	 * @param {Number} position - The absolute position to convert.
17339	 * @returns {Number} - The converted position.
17340	 */
17341	Owl.prototype.relative = function(position) {
17342		position -= this._clones.length / 2;
17343		return this.normalize(position, true);
17344	};
17345
17346	/**
17347	 * Gets the maximum position for the current item.
17348	 * @public
17349	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
17350	 * @returns {Number}
17351	 */
17352	Owl.prototype.maximum = function(relative) {
17353		var settings = this.settings,
17354			maximum = this._coordinates.length,
17355			boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
17356			i = -1, j;
17357
17358		if (settings.loop) {
17359			maximum = this._clones.length / 2 + this._items.length - 1;
17360		} else if (settings.autoWidth || settings.merge) {
17361			// binary search
17362			while (maximum - i > 1) {
17363				Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
17364					? i = j : maximum = j;
17365			}
17366		} else if (settings.center) {
17367			maximum = this._items.length - 1;
17368		} else {
17369			maximum = this._items.length - settings.items;
17370		}
17371
17372		if (relative) {
17373			maximum -= this._clones.length / 2;
17374		}
17375
17376		return Math.max(maximum, 0);
17377	};
17378
17379	/**
17380	 * Gets the minimum position for the current item.
17381	 * @public
17382	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
17383	 * @returns {Number}
17384	 */
17385	Owl.prototype.minimum = function(relative) {
17386		return relative ? 0 : this._clones.length / 2;
17387	};
17388
17389	/**
17390	 * Gets an item at the specified relative position.
17391	 * @public
17392	 * @param {Number} [position] - The relative position of the item.
17393	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
17394	 */
17395	Owl.prototype.items = function(position) {
17396		if (position === undefined) {
17397			return this._items.slice();
17398		}
17399
17400		position = this.normalize(position, true);
17401		return this._items[position];
17402	};
17403
17404	/**
17405	 * Gets an item at the specified relative position.
17406	 * @public
17407	 * @param {Number} [position] - The relative position of the item.
17408	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
17409	 */
17410	Owl.prototype.mergers = function(position) {
17411		if (position === undefined) {
17412			return this._mergers.slice();
17413		}
17414
17415		position = this.normalize(position, true);
17416		return this._mergers[position];
17417	};
17418
17419	/**
17420	 * Gets the absolute positions of clones for an item.
17421	 * @public
17422	 * @param {Number} [position] - The relative position of the item.
17423	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
17424	 */
17425	Owl.prototype.clones = function(position) {
17426		var odd = this._clones.length / 2,
17427			even = odd + this._items.length,
17428			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
17429
17430		if (position === undefined) {
17431			return $.map(this._clones, function(v, i) { return map(i) });
17432		}
17433
17434		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
17435	};
17436
17437	/**
17438	 * Sets the current animation speed.
17439	 * @public
17440	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
17441	 * @returns {Number} - The current animation speed in milliseconds.
17442	 */
17443	Owl.prototype.speed = function(speed) {
17444		if (speed !== undefined) {
17445			this._speed = speed;
17446		}
17447
17448		return this._speed;
17449	};
17450
17451	/**
17452	 * Gets the coordinate of an item.
17453	 * @todo The name of this method is missleanding.
17454	 * @public
17455	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
17456	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
17457	 */
17458	Owl.prototype.coordinates = function(position) {
17459		var coordinate = null;
17460
17461		if (position === undefined) {
17462			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
17463				return this.coordinates(index);
17464			}, this));
17465		}
17466
17467		if (this.settings.center) {
17468			coordinate = this._coordinates[position];
17469			coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
17470		} else {
17471			coordinate = this._coordinates[position - 1] || 0;
17472		}
17473
17474		return coordinate;
17475	};
17476
17477	/**
17478	 * Calculates the speed for a translation.
17479	 * @protected
17480	 * @param {Number} from - The absolute position of the start item.
17481	 * @param {Number} to - The absolute position of the target item.
17482	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
17483	 * @returns {Number} - The time in milliseconds for the translation.
17484	 */
17485	Owl.prototype.duration = function(from, to, factor) {
17486		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
17487	};
17488
17489	/**
17490	 * Slides to the specified item.
17491	 * @public
17492	 * @param {Number} position - The position of the item.
17493	 * @param {Number} [speed] - The time in milliseconds for the transition.
17494	 */
17495	Owl.prototype.to = function(position, speed) {
17496		var current = this.current(),
17497			revert = null,
17498			distance = position - this.relative(current),
17499			direction = (distance > 0) - (distance < 0),
17500			items = this._items.length,
17501			minimum = this.minimum(),
17502			maximum = this.maximum();
17503
17504		if (this.settings.loop) {
17505			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
17506				distance += direction * -1 * items;
17507			}
17508
17509			position = current + distance;
17510			revert = ((position - minimum) % items + items) % items + minimum;
17511
17512			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
17513				current = revert - distance;
17514				position = revert;
17515				this.reset(current);
17516			}
17517		} else if (this.settings.rewind) {
17518			maximum += 1;
17519			position = (position % maximum + maximum) % maximum;
17520		} else {
17521			position = Math.max(minimum, Math.min(maximum, position));
17522		}
17523
17524		this.speed(this.duration(current, position, speed));
17525		this.current(position);
17526
17527		if (this.$element.is(':visible')) {
17528			this.update();
17529		}
17530	};
17531
17532	/**
17533	 * Slides to the next item.
17534	 * @public
17535	 * @param {Number} [speed] - The time in milliseconds for the transition.
17536	 */
17537	Owl.prototype.next = function(speed) {
17538		speed = speed || false;
17539		this.to(this.relative(this.current()) + 1, speed);
17540	};
17541
17542	/**
17543	 * Slides to the previous item.
17544	 * @public
17545	 * @param {Number} [speed] - The time in milliseconds for the transition.
17546	 */
17547	Owl.prototype.prev = function(speed) {
17548		speed = speed || false;
17549		this.to(this.relative(this.current()) - 1, speed);
17550	};
17551
17552	/**
17553	 * Handles the end of an animation.
17554	 * @protected
17555	 * @param {Event} event - The event arguments.
17556	 */
17557	Owl.prototype.onTransitionEnd = function(event) {
17558
17559		// if css2 animation then event object is undefined
17560		if (event !== undefined) {
17561			event.stopPropagation();
17562
17563			// Catch only owl-stage transitionEnd event
17564			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
17565				return false;
17566			}
17567		}
17568
17569		this.leave('animating');
17570		this.trigger('translated');
17571	};
17572
17573	/**
17574	 * Gets viewport width.
17575	 * @protected
17576	 * @return {Number} - The width in pixel.
17577	 */
17578	Owl.prototype.viewport = function() {
17579		var width;
17580		if (this.options.responsiveBaseElement !== window) {
17581			width = $(this.options.responsiveBaseElement).width();
17582		} else if (window.innerWidth) {
17583			width = window.innerWidth;
17584		} else if (document.documentElement && document.documentElement.clientWidth) {
17585			width = document.documentElement.clientWidth;
17586		} else {
17587			throw 'Can not detect viewport width.';
17588		}
17589
17590		return width;
17591	};
17592
17593	/**
17594	 * Replaces the current content.
17595	 * @public
17596	 * @param {HTMLElement|jQuery|String} content - The new content.
17597	 */
17598	Owl.prototype.replace = function(content) {
17599		this.$stage.empty();
17600		this._items = [];
17601
17602		if (content) {
17603			content = (content instanceof jQuery) ? content : $(content);
17604		}
17605
17606		if (this.settings.nestedItemSelector) {
17607			content = content.find('.' + this.settings.nestedItemSelector);
17608		}
17609
17610		content.filter(function() {
17611			return this.nodeType === 1;
17612		}).each($.proxy(function(index, item) {
17613			item = this.prepare(item, index);
17614			this.$stage.append(item);
17615			this._items.push(item);
17616			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
17617		}, this));
17618
17619		this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
17620
17621		this.invalidate('items');
17622	};
17623
17624	/**
17625	 * Adds an item.
17626	 * @todo Use `item` instead of `content` for the event arguments.
17627	 * @public
17628	 * @param {HTMLElement|jQuery|String} content - The item content to add.
17629	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
17630	 */
17631	Owl.prototype.add = function(content, position) {
17632		var current = this.relative(this._current);
17633
17634		position = position === undefined ? this._items.length : this.normalize(position, true);
17635		content = content instanceof jQuery ? content : $(content);
17636
17637		this.trigger('add', { content: content, position: position });
17638
17639		content = this.prepare(content, this._items[current].index());
17640
17641		if (this._items.length === 0 || position === this._items.length) {
17642			this._items.length === 0 && this.$stage.append(content);
17643			this._items.length !== 0 && this._items[position - 1].after(content);
17644			this._items.push(content);
17645			this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
17646		} else {
17647			this._items[position].before(content);
17648			this._items.splice(position, 0, content);
17649			this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
17650		}
17651
17652		this._items[current] && this.reset(this._items[current].index());
17653
17654		this.invalidate('items');
17655
17656		this.trigger('added', { content: content, position: position });
17657	};
17658
17659	/**
17660	 * Removes an item by its position.
17661	 * @todo Use `item` instead of `content` for the event arguments.
17662	 * @public
17663	 * @param {Number} position - The relative position of the item to remove.
17664	 */
17665	Owl.prototype.remove = function(position) {
17666		position = this.normalize(position, true);
17667
17668		if (position === undefined) {
17669			return;
17670		}
17671
17672		this.trigger('remove', { content: this._items[position], position: position });
17673
17674		this._items[position].remove();
17675		this._items.splice(position, 1);
17676		this._mergers.splice(position, 1);
17677
17678		this.invalidate('items');
17679
17680		this.trigger('removed', { content: null, position: position });
17681	};
17682
17683	/**
17684	 * Preloads images with auto width.
17685	 * @todo Replace by a more generic approach
17686	 * @protected
17687	 */
17688	Owl.prototype.preloadAutoWidthImages = function(images) {
17689		images.each($.proxy(function(i, element) {
17690			this.enter('pre-loading');
17691			element = $(element);
17692			$(new Image()).one('load', $.proxy(function(e) {
17693				element.attr('src', e.target.src);
17694				element.css('opacity', 1);
17695				this.leave('pre-loading');
17696				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
17697			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
17698		}, this));
17699	};
17700
17701	/**
17702	 * Destroys the carousel.
17703	 * @public
17704	 */
17705	Owl.prototype.destroy = function() {
17706
17707		this.$element.off('.owl.core');
17708		this.$stage.off('.owl.core');
17709		$(document).off('.owl.core');
17710
17711		if (this.settings.responsive !== false) {
17712			window.clearTimeout(this.resizeTimer);
17713			this.off(window, 'resize', this._handlers.onThrottledResize);
17714		}
17715
17716		for (var i in this._plugins) {
17717			this._plugins[i].destroy();
17718		}
17719
17720		this.$stage.children('.cloned').remove();
17721
17722		this.$stage.unwrap();
17723		this.$stage.children().contents().unwrap();
17724		this.$stage.children().unwrap();
17725
17726		this.$element
17727			.removeClass(this.options.refreshClass)
17728			.removeClass(this.options.loadingClass)
17729			.removeClass(this.options.loadedClass)
17730			.removeClass(this.options.rtlClass)
17731			.removeClass(this.options.dragClass)
17732			.removeClass(this.options.grabClass)
17733			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
17734			.removeData('owl.carousel');
17735	};
17736
17737	/**
17738	 * Operators to calculate right-to-left and left-to-right.
17739	 * @protected
17740	 * @param {Number} [a] - The left side operand.
17741	 * @param {String} [o] - The operator.
17742	 * @param {Number} [b] - The right side operand.
17743	 */
17744	Owl.prototype.op = function(a, o, b) {
17745		var rtl = this.settings.rtl;
17746		switch (o) {
17747			case '<':
17748				return rtl ? a > b : a < b;
17749			case '>':
17750				return rtl ? a < b : a > b;
17751			case '>=':
17752				return rtl ? a <= b : a >= b;
17753			case '<=':
17754				return rtl ? a >= b : a <= b;
17755			default:
17756				break;
17757		}
17758	};
17759
17760	/**
17761	 * Attaches to an internal event.
17762	 * @protected
17763	 * @param {HTMLElement} element - The event source.
17764	 * @param {String} event - The event name.
17765	 * @param {Function} listener - The event handler to attach.
17766	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
17767	 */
17768	Owl.prototype.on = function(element, event, listener, capture) {
17769		if (element.addEventListener) {
17770			element.addEventListener(event, listener, capture);
17771		} else if (element.attachEvent) {
17772			element.attachEvent('on' + event, listener);
17773		}
17774	};
17775
17776	/**
17777	 * Detaches from an internal event.
17778	 * @protected
17779	 * @param {HTMLElement} element - The event source.
17780	 * @param {String} event - The event name.
17781	 * @param {Function} listener - The attached event handler to detach.
17782	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
17783	 */
17784	Owl.prototype.off = function(element, event, listener, capture) {
17785		if (element.removeEventListener) {
17786			element.removeEventListener(event, listener, capture);
17787		} else if (element.detachEvent) {
17788			element.detachEvent('on' + event, listener);
17789		}
17790	};
17791
17792	/**
17793	 * Triggers a public event.
17794	 * @todo Remove `status`, `relatedTarget` should be used instead.
17795	 * @protected
17796	 * @param {String} name - The event name.
17797	 * @param {*} [data=null] - The event data.
17798	 * @param {String} [namespace=carousel] - The event namespace.
17799	 * @param {String} [state] - The state which is associated with the event.
17800	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
17801	 * @returns {Event} - The event arguments.
17802	 */
17803	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
17804		var status = {
17805			item: { count: this._items.length, index: this.current() }
17806		}, handler = $.camelCase(
17807			$.grep([ 'on', name, namespace ], function(v) { return v })
17808				.join('-').toLowerCase()
17809		), event = $.Event(
17810			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
17811			$.extend({ relatedTarget: this }, status, data)
17812		);
17813
17814		if (!this._supress[name]) {
17815			$.each(this._plugins, function(name, plugin) {
17816				if (plugin.onTrigger) {
17817					plugin.onTrigger(event);
17818				}
17819			});
17820
17821			this.register({ type: Owl.Type.Event, name: name });
17822			this.$element.trigger(event);
17823
17824			if (this.settings && typeof this.settings[handler] === 'function') {
17825				this.settings[handler].call(this, event);
17826			}
17827		}
17828
17829		return event;
17830	};
17831
17832	/**
17833	 * Enters a state.
17834	 * @param name - The state name.
17835	 */
17836	Owl.prototype.enter = function(name) {
17837		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
17838			if (this._states.current[name] === undefined) {
17839				this._states.current[name] = 0;
17840			}
17841
17842			this._states.current[name]++;
17843		}, this));
17844	};
17845
17846	/**
17847	 * Leaves a state.
17848	 * @param name - The state name.
17849	 */
17850	Owl.prototype.leave = function(name) {
17851		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
17852			this._states.current[name]--;
17853		}, this));
17854	};
17855
17856	/**
17857	 * Registers an event or state.
17858	 * @public
17859	 * @param {Object} object - The event or state to register.
17860	 */
17861	Owl.prototype.register = function(object) {
17862		if (object.type === Owl.Type.Event) {
17863			if (!$.event.special[object.name]) {
17864				$.event.special[object.name] = {};
17865			}
17866
17867			if (!$.event.special[object.name].owl) {
17868				var _default = $.event.special[object.name]._default;
17869				$.event.special[object.name]._default = function(e) {
17870					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
17871						return _default.apply(this, arguments);
17872					}
17873					return e.namespace && e.namespace.indexOf('owl') > -1;
17874				};
17875				$.event.special[object.name].owl = true;
17876			}
17877		} else if (object.type === Owl.Type.State) {
17878			if (!this._states.tags[object.name]) {
17879				this._states.tags[object.name] = object.tags;
17880			} else {
17881				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
17882			}
17883
17884			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
17885				return $.inArray(tag, this._states.tags[object.name]) === i;
17886			}, this));
17887		}
17888	};
17889
17890	/**
17891	 * Suppresses events.
17892	 * @protected
17893	 * @param {Array.<String>} events - The events to suppress.
17894	 */
17895	Owl.prototype.suppress = function(events) {
17896		$.each(events, $.proxy(function(index, event) {
17897			this._supress[event] = true;
17898		}, this));
17899	};
17900
17901	/**
17902	 * Releases suppressed events.
17903	 * @protected
17904	 * @param {Array.<String>} events - The events to release.
17905	 */
17906	Owl.prototype.release = function(events) {
17907		$.each(events, $.proxy(function(index, event) {
17908			delete this._supress[event];
17909		}, this));
17910	};
17911
17912	/**
17913	 * Gets unified pointer coordinates from event.
17914	 * @todo #261
17915	 * @protected
17916	 * @param {Event} - The `mousedown` or `touchstart` event.
17917	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
17918	 */
17919	Owl.prototype.pointer = function(event) {
17920		var result = { x: null, y: null };
17921
17922		event = event.originalEvent || event || window.event;
17923
17924		event = event.touches && event.touches.length ?
17925			event.touches[0] : event.changedTouches && event.changedTouches.length ?
17926				event.changedTouches[0] : event;
17927
17928		if (event.pageX) {
17929			result.x = event.pageX;
17930			result.y = event.pageY;
17931		} else {
17932			result.x = event.clientX;
17933			result.y = event.clientY;
17934		}
17935
17936		return result;
17937	};
17938
17939	/**
17940	 * Gets the difference of two vectors.
17941	 * @todo #261
17942	 * @protected
17943	 * @param {Object} - The first vector.
17944	 * @param {Object} - The second vector.
17945	 * @returns {Object} - The difference.
17946	 */
17947	Owl.prototype.difference = function(first, second) {
17948		return {
17949			x: first.x - second.x,
17950			y: first.y - second.y
17951		};
17952	};
17953
17954	/**
17955	 * The jQuery Plugin for the Owl Carousel
17956	 * @todo Navigation plugin `next` and `prev`
17957	 * @public
17958	 */
17959	$.fn.owlCarousel = function(option) {
17960		var args = Array.prototype.slice.call(arguments, 1);
17961
17962		return this.each(function() {
17963			var $this = $(this),
17964				data = $this.data('owl.carousel');
17965
17966			if (!data) {
17967				data = new Owl(this, typeof option == 'object' && option);
17968				$this.data('owl.carousel', data);
17969
17970				$.each([
17971					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
17972				], function(i, event) {
17973					data.register({ type: Owl.Type.Event, name: event });
17974					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
17975						if (e.namespace && e.relatedTarget !== this) {
17976							this.suppress([ event ]);
17977							data[event].apply(this, [].slice.call(arguments, 1));
17978							this.release([ event ]);
17979						}
17980					}, data));
17981				});
17982			}
17983
17984			if (typeof option == 'string' && option.charAt(0) !== '_') {
17985				data[option].apply(data, args);
17986			}
17987		});
17988	};
17989
17990	/**
17991	 * The constructor for the jQuery Plugin
17992	 * @public
17993	 */
17994	$.fn.owlCarousel.Constructor = Owl;
17995
17996})(window.Zepto || window.jQuery, window, document);
17997
17998/**
17999 * AutoRefresh Plugin
18000 * @version 2.0.0-beta.3
18001 * @author Artus Kolanowski
18002 * @license The MIT License (MIT)
18003 */
18004;(function($, window, document, undefined) {
18005
18006	/**
18007	 * Creates the auto refresh plugin.
18008	 * @class The Auto Refresh Plugin
18009	 * @param {Owl} carousel - The Owl Carousel
18010	 */
18011	var AutoRefresh = function(carousel) {
18012		/**
18013		 * Reference to the core.
18014		 * @protected
18015		 * @type {Owl}
18016		 */
18017		this._core = carousel;
18018
18019		/**
18020		 * Refresh interval.
18021		 * @protected
18022		 * @type {number}
18023		 */
18024		this._interval = null;
18025
18026		/**
18027		 * Whether the element is currently visible or not.
18028		 * @protected
18029		 * @type {Boolean}
18030		 */
18031		this._visible = null;
18032
18033		/**
18034		 * All event handlers.
18035		 * @protected
18036		 * @type {Object}
18037		 */
18038		this._handlers = {
18039			'initialized.owl.carousel': $.proxy(function(e) {
18040				if (e.namespace && this._core.settings.autoRefresh) {
18041					this.watch();
18042				}
18043			}, this)
18044		};
18045
18046		// set default options
18047		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
18048
18049		// register event handlers
18050		this._core.$element.on(this._handlers);
18051	};
18052
18053	/**
18054	 * Default options.
18055	 * @public
18056	 */
18057	AutoRefresh.Defaults = {
18058		autoRefresh: true,
18059		autoRefreshInterval: 500
18060	};
18061
18062	/**
18063	 * Watches the element.
18064	 */
18065	AutoRefresh.prototype.watch = function() {
18066		if (this._interval) {
18067			return;
18068		}
18069
18070		this._visible = this._core.$element.is(':visible');
18071		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
18072	};
18073
18074	/**
18075	 * Refreshes the element.
18076	 */
18077	AutoRefresh.prototype.refresh = function() {
18078		if (this._core.$element.is(':visible') === this._visible) {
18079			return;
18080		}
18081
18082		this._visible = !this._visible;
18083
18084		this._core.$element.toggleClass('owl-hidden', !this._visible);
18085
18086		this._visible && (this._core.invalidate('width') && this._core.refresh());
18087	};
18088
18089	/**
18090	 * Destroys the plugin.
18091	 */
18092	AutoRefresh.prototype.destroy = function() {
18093		var handler, property;
18094
18095		window.clearInterval(this._interval);
18096
18097		for (handler in this._handlers) {
18098			this._core.$element.off(handler, this._handlers[handler]);
18099		}
18100		for (property in Object.getOwnPropertyNames(this)) {
18101			typeof this[property] != 'function' && (this[property] = null);
18102		}
18103	};
18104
18105	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
18106
18107})(window.Zepto || window.jQuery, window, document);
18108
18109/**
18110 * Lazy Plugin
18111 * @version 2.0.0-beta.3
18112 * @author Bartosz Wojciechowski
18113 * @license The MIT License (MIT)
18114 */
18115;(function($, window, document, undefined) {
18116
18117	/**
18118	 * Creates the lazy plugin.
18119	 * @class The Lazy Plugin
18120	 * @param {Owl} carousel - The Owl Carousel
18121	 */
18122	var Lazy = function(carousel) {
18123
18124		/**
18125		 * Reference to the core.
18126		 * @protected
18127		 * @type {Owl}
18128		 */
18129		this._core = carousel;
18130
18131		/**
18132		 * Already loaded items.
18133		 * @protected
18134		 * @type {Array.<jQuery>}
18135		 */
18136		this._loaded = [];
18137
18138		/**
18139		 * Event handlers.
18140		 * @protected
18141		 * @type {Object}
18142		 */
18143		this._handlers = {
18144			'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
18145				if (!e.namespace) {
18146					return;
18147				}
18148
18149				if (!this._core.settings || !this._core.settings.lazyLoad) {
18150					return;
18151				}
18152
18153				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
18154					var settings = this._core.settings,
18155						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
18156						i = ((settings.center && n * -1) || 0),
18157						position = ((e.property && e.property.value) || this._core.current()) + i,
18158						clones = this._core.clones().length,
18159						load = $.proxy(function(i, v) { this.load(v) }, this);
18160
18161					while (i++ < n) {
18162						this.load(clones / 2 + this._core.relative(position));
18163						clones && $.each(this._core.clones(this._core.relative(position)), load);
18164						position++;
18165					}
18166				}
18167			}, this)
18168		};
18169
18170		// set the default options
18171		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
18172
18173		// register event handler
18174		this._core.$element.on(this._handlers);
18175	}
18176
18177	/**
18178	 * Default options.
18179	 * @public
18180	 */
18181	Lazy.Defaults = {
18182		lazyLoad: false
18183	}
18184
18185	/**
18186	 * Loads all resources of an item at the specified position.
18187	 * @param {Number} position - The absolute position of the item.
18188	 * @protected
18189	 */
18190	Lazy.prototype.load = function(position) {
18191		var $item = this._core.$stage.children().eq(position),
18192			$elements = $item && $item.find('.owl-lazy');
18193
18194		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
18195			return;
18196		}
18197
18198		$elements.each($.proxy(function(index, element) {
18199			var $element = $(element), image,
18200				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
18201
18202			this._core.trigger('load', { element: $element, url: url }, 'lazy');
18203
18204			if ($element.is('img')) {
18205				$element.one('load.owl.lazy', $.proxy(function() {
18206					$element.css('opacity', 1);
18207					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
18208				}, this)).attr('src', url);
18209			} else {
18210				image = new Image();
18211				image.onload = $.proxy(function() {
18212					$element.css({
18213						'background-image': 'url(' + url + ')',
18214						'opacity': '1'
18215					});
18216					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
18217				}, this);
18218				image.src = url;
18219			}
18220		}, this));
18221
18222		this._loaded.push($item.get(0));
18223	}
18224
18225	/**
18226	 * Destroys the plugin.
18227	 * @public
18228	 */
18229	Lazy.prototype.destroy = function() {
18230		var handler, property;
18231
18232		for (handler in this.handlers) {
18233			this._core.$element.off(handler, this.handlers[handler]);
18234		}
18235		for (property in Object.getOwnPropertyNames(this)) {
18236			typeof this[property] != 'function' && (this[property] = null);
18237		}
18238	};
18239
18240	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
18241
18242})(window.Zepto || window.jQuery, window, document);
18243
18244/**
18245 * AutoHeight Plugin
18246 * @version 2.0.0-beta.3
18247 * @author Bartosz Wojciechowski
18248 * @license The MIT License (MIT)
18249 */
18250;(function($, window, document, undefined) {
18251
18252	/**
18253	 * Creates the auto height plugin.
18254	 * @class The Auto Height Plugin
18255	 * @param {Owl} carousel - The Owl Carousel
18256	 */
18257	var AutoHeight = function(carousel) {
18258		/**
18259		 * Reference to the core.
18260		 * @protected
18261		 * @type {Owl}
18262		 */
18263		this._core = carousel;
18264
18265		/**
18266		 * All event handlers.
18267		 * @protected
18268		 * @type {Object}
18269		 */
18270		this._handlers = {
18271			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
18272				if (e.namespace && this._core.settings.autoHeight) {
18273					this.update();
18274				}
18275			}, this),
18276			'changed.owl.carousel': $.proxy(function(e) {
18277				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
18278					this.update();
18279				}
18280			}, this),
18281			'loaded.owl.lazy': $.proxy(function(e) {
18282				if (e.namespace && this._core.settings.autoHeight
18283					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
18284					this.update();
18285				}
18286			}, this)
18287		};
18288
18289		// set default options
18290		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
18291
18292		// register event handlers
18293		this._core.$element.on(this._handlers);
18294	};
18295
18296	/**
18297	 * Default options.
18298	 * @public
18299	 */
18300	AutoHeight.Defaults = {
18301		autoHeight: false,
18302		autoHeightClass: 'owl-height'
18303	};
18304
18305	/**
18306	 * Updates the view.
18307	 */
18308	AutoHeight.prototype.update = function() {
18309		var start = this._core._current,
18310			end = start + this._core.settings.items,
18311			visible = this._core.$stage.children().toArray().slice(start, end);
18312			heights = [],
18313			maxheight = 0;
18314
18315		$.each(visible, function(index, item) {
18316			heights.push($(item).height());
18317		});
18318
18319		maxheight = Math.max.apply(null, heights);
18320
18321		this._core.$stage.parent()
18322			.height(maxheight)
18323			.addClass(this._core.settings.autoHeightClass);
18324	};
18325
18326	AutoHeight.prototype.destroy = function() {
18327		var handler, property;
18328
18329		for (handler in this._handlers) {
18330			this._core.$element.off(handler, this._handlers[handler]);
18331		}
18332		for (property in Object.getOwnPropertyNames(this)) {
18333			typeof this[property] != 'function' && (this[property] = null);
18334		}
18335	};
18336
18337	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
18338
18339})(window.Zepto || window.jQuery, window, document);
18340
18341/**
18342 * Video Plugin
18343 * @version 2.0.0-beta.3
18344 * @author Bartosz Wojciechowski
18345 * @license The MIT License (MIT)
18346 */
18347;(function($, window, document, undefined) {
18348
18349	/**
18350	 * Creates the video plugin.
18351	 * @class The Video Plugin
18352	 * @param {Owl} carousel - The Owl Carousel
18353	 */
18354	var Video = function(carousel) {
18355		/**
18356		 * Reference to the core.
18357		 * @protected
18358		 * @type {Owl}
18359		 */
18360		this._core = carousel;
18361
18362		/**
18363		 * Cache all video URLs.
18364		 * @protected
18365		 * @type {Object}
18366		 */
18367		this._videos = {};
18368
18369		/**
18370		 * Current playing item.
18371		 * @protected
18372		 * @type {jQuery}
18373		 */
18374		this._playing = null;
18375
18376		/**
18377		 * All event handlers.
18378		 * @todo The cloned content removale is too late
18379		 * @protected
18380		 * @type {Object}
18381		 */
18382		this._handlers = {
18383			'initialized.owl.carousel': $.proxy(function(e) {
18384				if (e.namespace) {
18385					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
18386				}
18387			}, this),
18388			'resize.owl.carousel': $.proxy(function(e) {
18389				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
18390					e.preventDefault();
18391				}
18392			}, this),
18393			'refreshed.owl.carousel': $.proxy(function(e) {
18394				if (e.namespace && this._core.is('resizing')) {
18395					this._core.$stage.find('.cloned .owl-video-frame').remove();
18396				}
18397			}, this),
18398			'changed.owl.carousel': $.proxy(function(e) {
18399				if (e.namespace && e.property.name === 'position' && this._playing) {
18400					this.stop();
18401				}
18402			}, this),
18403			'prepared.owl.carousel': $.proxy(function(e) {
18404				if (!e.namespace) {
18405					return;
18406				}
18407
18408				var $element = $(e.content).find('.owl-video');
18409
18410				if ($element.length) {
18411					$element.css('display', 'none');
18412					this.fetch($element, $(e.content));
18413				}
18414			}, this)
18415		};
18416
18417		// set default options
18418		this._core.options = $.extend({}, Video.Defaults, this._core.options);
18419
18420		// register event handlers
18421		this._core.$element.on(this._handlers);
18422
18423		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
18424			this.play(e);
18425		}, this));
18426	};
18427
18428	/**
18429	 * Default options.
18430	 * @public
18431	 */
18432	Video.Defaults = {
18433		video: false,
18434		videoHeight: false,
18435		videoWidth: false
18436	};
18437
18438	/**
18439	 * Gets the video ID and the type (YouTube/Vimeo only).
18440	 * @protected
18441	 * @param {jQuery} target - The target containing the video data.
18442	 * @param {jQuery} item - The item containing the video.
18443	 */
18444	Video.prototype.fetch = function(target, item) {
18445		var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
18446			id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
18447			width = target.attr('data-width') || this._core.settings.videoWidth,
18448			height = target.attr('data-height') || this._core.settings.videoHeight,
18449			url = target.attr('href');
18450
18451		if (url) {
18452			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+)?/);
18453
18454			if (id[3].indexOf('youtu') > -1) {
18455				type = 'youtube';
18456			} else if (id[3].indexOf('vimeo') > -1) {
18457				type = 'vimeo';
18458			} else {
18459				throw new Error('Video URL not supported.');
18460			}
18461			id = id[6];
18462		} else {
18463			throw new Error('Missing video URL.');
18464		}
18465
18466		this._videos[url] = {
18467			type: type,
18468			id: id,
18469			width: width,
18470			height: height
18471		};
18472
18473		item.attr('data-video', url);
18474
18475		this.thumbnail(target, this._videos[url]);
18476	};
18477
18478	/**
18479	 * Creates video thumbnail.
18480	 * @protected
18481	 * @param {jQuery} target - The target containing the video data.
18482	 * @param {Object} info - The video info object.
18483	 * @see `fetch`
18484	 */
18485	Video.prototype.thumbnail = function(target, video) {
18486		var tnLink,
18487			icon,
18488			path,
18489			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
18490			customTn = target.find('img'),
18491			srcType = 'src',
18492			lazyClass = '',
18493			settings = this._core.settings,
18494			create = function(path) {
18495				icon = '<div class="owl-video-play-icon"></div>';
18496
18497				if (settings.lazyLoad) {
18498					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
18499				} else {
18500					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
18501				}
18502				target.after(tnLink);
18503				target.after(icon);
18504			};
18505
18506		// wrap video content into owl-video-wrapper div
18507		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
18508
18509		if (this._core.settings.lazyLoad) {
18510			srcType = 'data-src';
18511			lazyClass = 'owl-lazy';
18512		}
18513
18514		// custom thumbnail
18515		if (customTn.length) {
18516			create(customTn.attr(srcType));
18517			customTn.remove();
18518			return false;
18519		}
18520
18521		if (video.type === 'youtube') {
18522			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
18523			create(path);
18524		} else if (video.type === 'vimeo') {
18525			$.ajax({
18526				type: 'GET',
18527				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
18528				jsonp: 'callback',
18529				dataType: 'jsonp',
18530				success: function(data) {
18531					path = data[0].thumbnail_large;
18532					create(path);
18533				}
18534			});
18535		}
18536	};
18537
18538	/**
18539	 * Stops the current video.
18540	 * @public
18541	 */
18542	Video.prototype.stop = function() {
18543		this._core.trigger('stop', null, 'video');
18544		this._playing.find('.owl-video-frame').remove();
18545		this._playing.removeClass('owl-video-playing');
18546		this._playing = null;
18547		this._core.leave('playing');
18548		this._core.trigger('stopped', null, 'video');
18549	};
18550
18551	/**
18552	 * Starts the current video.
18553	 * @public
18554	 * @param {Event} event - The event arguments.
18555	 */
18556	Video.prototype.play = function(event) {
18557		var target = $(event.target),
18558			item = target.closest('.' + this._core.settings.itemClass),
18559			video = this._videos[item.attr('data-video')],
18560			width = video.width || '100%',
18561			height = video.height || this._core.$stage.height(),
18562			html;
18563
18564		if (this._playing) {
18565			return;
18566		}
18567
18568		this._core.enter('playing');
18569		this._core.trigger('play', null, 'video');
18570
18571		item = this._core.items(this._core.relative(item.index()));
18572
18573		this._core.reset(item.index());
18574
18575		if (video.type === 'youtube') {
18576			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
18577				video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
18578		} else if (video.type === 'vimeo') {
18579			html = '<iframe src="//player.vimeo.com/video/' + video.id +
18580				'?autoplay=1" width="' + width + '" height="' + height +
18581				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
18582		}
18583
18584		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
18585
18586		this._playing = item.addClass('owl-video-playing');
18587	};
18588
18589	/**
18590	 * Checks whether an video is currently in full screen mode or not.
18591	 * @todo Bad style because looks like a readonly method but changes members.
18592	 * @protected
18593	 * @returns {Boolean}
18594	 */
18595	Video.prototype.isInFullScreen = function() {
18596		var element = document.fullscreenElement || document.mozFullScreenElement ||
18597				document.webkitFullscreenElement;
18598
18599		return element && $(element).parent().hasClass('owl-video-frame');
18600	};
18601
18602	/**
18603	 * Destroys the plugin.
18604	 */
18605	Video.prototype.destroy = function() {
18606		var handler, property;
18607
18608		this._core.$element.off('click.owl.video');
18609
18610		for (handler in this._handlers) {
18611			this._core.$element.off(handler, this._handlers[handler]);
18612		}
18613		for (property in Object.getOwnPropertyNames(this)) {
18614			typeof this[property] != 'function' && (this[property] = null);
18615		}
18616	};
18617
18618	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
18619
18620})(window.Zepto || window.jQuery, window, document);
18621
18622/**
18623 * Animate Plugin
18624 * @version 2.0.0-beta.3
18625 * @author Bartosz Wojciechowski
18626 * @license The MIT License (MIT)
18627 */
18628;(function($, window, document, undefined) {
18629
18630	/**
18631	 * Creates the animate plugin.
18632	 * @class The Navigation Plugin
18633	 * @param {Owl} scope - The Owl Carousel
18634	 */
18635	var Animate = function(scope) {
18636		this.core = scope;
18637		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
18638		this.swapping = true;
18639		this.previous = undefined;
18640		this.next = undefined;
18641
18642		this.handlers = {
18643			'change.owl.carousel': $.proxy(function(e) {
18644				if (e.namespace && e.property.name == 'position') {
18645					this.previous = this.core.current();
18646					this.next = e.property.value;
18647				}
18648			}, this),
18649			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
18650				if (e.namespace) {
18651					this.swapping = e.type == 'translated';
18652				}
18653			}, this),
18654			'translate.owl.carousel': $.proxy(function(e) {
18655				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
18656					this.swap();
18657				}
18658			}, this)
18659		};
18660
18661		this.core.$element.on(this.handlers);
18662	};
18663
18664	/**
18665	 * Default options.
18666	 * @public
18667	 */
18668	Animate.Defaults = {
18669		animateOut: false,
18670		animateIn: false
18671	};
18672
18673	/**
18674	 * Toggles the animation classes whenever an translations starts.
18675	 * @protected
18676	 * @returns {Boolean|undefined}
18677	 */
18678	Animate.prototype.swap = function() {
18679
18680		if (this.core.settings.items !== 1) {
18681			return;
18682		}
18683
18684		if (!$.support.animation || !$.support.transition) {
18685			return;
18686		}
18687
18688		this.core.speed(0);
18689
18690		var left,
18691			clear = $.proxy(this.clear, this),
18692			previous = this.core.$stage.children().eq(this.previous),
18693			next = this.core.$stage.children().eq(this.next),
18694			incoming = this.core.settings.animateIn,
18695			outgoing = this.core.settings.animateOut;
18696
18697		if (this.core.current() === this.previous) {
18698			return;
18699		}
18700
18701		if (outgoing) {
18702			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
18703			previous.css( { 'left': left + 'px' } )
18704				.addClass('animated owl-animated-out')
18705				.addClass(outgoing)
18706				.on($.support.animation.end, clear);
18707		}
18708
18709		if (incoming) {
18710			next.addClass('animated owl-animated-in')
18711				.addClass(incoming)
18712				.on($.support.animation.end, clear);
18713		}
18714	};
18715
18716	Animate.prototype.clear = function(e) {
18717		if ($(e.target).hasClass('animated')) {
18718			$(e.target).css( { 'left': '' } )
18719				.removeClass('animated owl-animated-out owl-animated-in')
18720				.removeClass(this.core.settings.animateIn)
18721				.removeClass(this.core.settings.animateOut);
18722			this.core.onTransitionEnd();
18723		}
18724	};
18725
18726	/**
18727	 * Destroys the plugin.
18728	 * @public
18729	 */
18730	Animate.prototype.destroy = function() {
18731		var handler, property;
18732
18733		for (handler in this.handlers) {
18734			this.core.$element.off(handler, this.handlers[handler]);
18735		}
18736		for (property in Object.getOwnPropertyNames(this)) {
18737			typeof this[property] != 'function' && (this[property] = null);
18738		}
18739	};
18740
18741	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
18742
18743})(window.Zepto || window.jQuery, window, document);
18744
18745/**
18746 * Autoplay Plugin
18747 * @version 2.0.0-beta.3
18748 * @author Bartosz Wojciechowski
18749 * @author Artus Kolanowski
18750 * @license The MIT License (MIT)
18751 */
18752;(function($, window, document, undefined) {
18753
18754	/**
18755	 * Creates the autoplay plugin.
18756	 * @class The Autoplay Plugin
18757	 * @param {Owl} scope - The Owl Carousel
18758	 */
18759	var Autoplay = function(carousel) {
18760		/**
18761		 * Reference to the core.
18762		 * @protected
18763		 * @type {Owl}
18764		 */
18765		this._core = carousel;
18766
18767		/**
18768		 * The autoplay interval.
18769		 * @type {Number}
18770		 */
18771		this._interval = null;
18772
18773		/**
18774		 * Indicates whenever the autoplay is paused.
18775		 * @type {Boolean}
18776		 */
18777		this._paused = false;
18778
18779		/**
18780		 * All event handlers.
18781		 * @protected
18782		 * @type {Object}
18783		 */
18784		this._handlers = {
18785			'changed.owl.carousel': $.proxy(function(e) {
18786				if (e.namespace && e.property.name === 'settings') {
18787					if (this._core.settings.autoplay) {
18788						this.play();
18789					} else {
18790						this.stop();
18791					}
18792				}
18793			}, this),
18794			'initialized.owl.carousel': $.proxy(function(e) {
18795				if (e.namespace && this._core.settings.autoplay) {
18796					this.play();
18797				}
18798			}, this),
18799			'play.owl.autoplay': $.proxy(function(e, t, s) {
18800				if (e.namespace) {
18801					this.play(t, s);
18802				}
18803			}, this),
18804			'stop.owl.autoplay': $.proxy(function(e) {
18805				if (e.namespace) {
18806					this.stop();
18807				}
18808			}, this),
18809			'mouseover.owl.autoplay': $.proxy(function() {
18810				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
18811					this.pause();
18812				}
18813			}, this),
18814			'mouseleave.owl.autoplay': $.proxy(function() {
18815				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
18816					this.play();
18817				}
18818			}, this)
18819		};
18820
18821		// register event handlers
18822		this._core.$element.on(this._handlers);
18823
18824		// set default options
18825		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
18826	};
18827
18828	/**
18829	 * Default options.
18830	 * @public
18831	 */
18832	Autoplay.Defaults = {
18833		autoplay: false,
18834		autoplayTimeout: 5000,
18835		autoplayHoverPause: false,
18836		autoplaySpeed: false
18837	};
18838
18839	/**
18840	 * Starts the autoplay.
18841	 * @public
18842	 * @param {Number} [timeout] - The interval before the next animation starts.
18843	 * @param {Number} [speed] - The animation speed for the animations.
18844	 */
18845	Autoplay.prototype.play = function(timeout, speed) {
18846		this._paused = false;
18847
18848		if (this._core.is('rotating')) {
18849			return;
18850		}
18851
18852		this._core.enter('rotating');
18853
18854		this._interval = window.setInterval($.proxy(function() {
18855			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
18856				return;
18857			}
18858			this._core.next(speed || this._core.settings.autoplaySpeed);
18859		}, this), timeout || this._core.settings.autoplayTimeout);
18860	};
18861
18862	/**
18863	 * Stops the autoplay.
18864	 * @public
18865	 */
18866	Autoplay.prototype.stop = function() {
18867		if (!this._core.is('rotating')) {
18868			return;
18869		}
18870
18871		window.clearInterval(this._interval);
18872		this._core.leave('rotating');
18873	};
18874
18875	/**
18876	 * Stops the autoplay.
18877	 * @public
18878	 */
18879	Autoplay.prototype.pause = function() {
18880		if (!this._core.is('rotating')) {
18881			return;
18882		}
18883
18884		this._paused = true;
18885	};
18886
18887	/**
18888	 * Destroys the plugin.
18889	 */
18890	Autoplay.prototype.destroy = function() {
18891		var handler, property;
18892
18893		this.stop();
18894
18895		for (handler in this._handlers) {
18896			this._core.$element.off(handler, this._handlers[handler]);
18897		}
18898		for (property in Object.getOwnPropertyNames(this)) {
18899			typeof this[property] != 'function' && (this[property] = null);
18900		}
18901	};
18902
18903	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
18904
18905})(window.Zepto || window.jQuery, window, document);
18906
18907/**
18908 * Navigation Plugin
18909 * @version 2.0.0-beta.3
18910 * @author Artus Kolanowski
18911 * @license The MIT License (MIT)
18912 */
18913;(function($, window, document, undefined) {
18914	'use strict';
18915
18916	/**
18917	 * Creates the navigation plugin.
18918	 * @class The Navigation Plugin
18919	 * @param {Owl} carousel - The Owl Carousel.
18920	 */
18921	var Navigation = function(carousel) {
18922		/**
18923		 * Reference to the core.
18924		 * @protected
18925		 * @type {Owl}
18926		 */
18927		this._core = carousel;
18928
18929		/**
18930		 * Indicates whether the plugin is initialized or not.
18931		 * @protected
18932		 * @type {Boolean}
18933		 */
18934		this._initialized = false;
vendor: 14,104 bytes, lines 18935-19463
18935
18936		/**
18937		 * The current paging indexes.
18938		 * @protected
18939		 * @type {Array}
18940		 */
18941		this._pages = [];
18942
18943		/**
18944		 * All DOM elements of the user interface.
18945		 * @protected
18946		 * @type {Object}
18947		 */
18948		this._controls = {};
18949
18950		/**
18951		 * Markup for an indicator.
18952		 * @protected
18953		 * @type {Array.<String>}
18954		 */
18955		this._templates = [];
18956
18957		/**
18958		 * The carousel element.
18959		 * @type {jQuery}
18960		 */
18961		this.$element = this._core.$element;
18962
18963		/**
18964		 * Overridden methods of the carousel.
18965		 * @protected
18966		 * @type {Object}
18967		 */
18968		this._overrides = {
18969			next: this._core.next,
18970			prev: this._core.prev,
18971			to: this._core.to
18972		};
18973
18974		/**
18975		 * All event handlers.
18976		 * @protected
18977		 * @type {Object}
18978		 */
18979		this._handlers = {
18980			'prepared.owl.carousel': $.proxy(function(e) {
18981				if (e.namespace && this._core.settings.dotsData) {
18982					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
18983						$(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot') + '</div>');
18984				}
18985			}, this),
18986			'added.owl.carousel': $.proxy(function(e) {
18987				if (e.namespace && this._core.settings.dotsData) {
18988					this._templates.splice(e.position, 0, this._templates.pop());
18989				}
18990			}, this),
18991			'remove.owl.carousel': $.proxy(function(e) {
18992				if (e.namespace && this._core.settings.dotsData) {
18993					this._templates.splice(e.position, 1);
18994				}
18995			}, this),
18996			'changed.owl.carousel': $.proxy(function(e) {
18997				if (e.namespace && e.property.name == 'position') {
18998					this.draw();
18999				}
19000			}, this),
19001			'initialized.owl.carousel': $.proxy(function(e) {
19002				if (e.namespace && !this._initialized) {
19003					this._core.trigger('initialize', null, 'navigation');
19004					this.initialize();
19005					this.update();
19006					this.draw();
19007					this._initialized = true;
19008					this._core.trigger('initialized', null, 'navigation');
19009				}
19010			}, this),
19011			'refreshed.owl.carousel': $.proxy(function(e) {
19012				if (e.namespace && this._initialized) {
19013					this._core.trigger('refresh', null, 'navigation');
19014					this.update();
19015					this.draw();
19016					this._core.trigger('refreshed', null, 'navigation');
19017				}
19018			}, this)
19019		};
19020
19021		// set default options
19022		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
19023
19024		// register event handlers
19025		this.$element.on(this._handlers);
19026	};
19027
19028	/**
19029	 * Default options.
19030	 * @public
19031	 * @todo Rename `slideBy` to `navBy`
19032	 */
19033	Navigation.Defaults = {
19034		nav: false,
19035		navText: [ 'prev', 'next' ],
19036		navSpeed: false,
19037		navElement: 'div',
19038		navContainer: false,
19039		navContainerClass: 'owl-nav',
19040		navClass: [ 'owl-prev', 'owl-next' ],
19041		slideBy: 1,
19042		dotClass: 'owl-dot',
19043		dotsClass: 'owl-dots',
19044		dots: true,
19045		dotsEach: false,
19046		dotsData: false,
19047		dotsSpeed: false,
19048		dotsContainer: false
19049	};
19050
19051	/**
19052	 * Initializes the layout of the plugin and extends the carousel.
19053	 * @protected
19054	 */
19055	Navigation.prototype.initialize = function() {
19056		var override,
19057			settings = this._core.settings;
19058
19059		// create DOM structure for relative navigation
19060		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
19061			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
19062
19063		this._controls.$previous = $('<' + settings.navElement + '>')
19064			.addClass(settings.navClass[0])
19065			.html(settings.navText[0])
19066			.prependTo(this._controls.$relative)
19067			.on('click', $.proxy(function(e) {
19068				this.prev(settings.navSpeed);
19069			}, this));
19070		this._controls.$next = $('<' + settings.navElement + '>')
19071			.addClass(settings.navClass[1])
19072			.html(settings.navText[1])
19073			.appendTo(this._controls.$relative)
19074			.on('click', $.proxy(function(e) {
19075				this.next(settings.navSpeed);
19076			}, this));
19077
19078		// create DOM structure for absolute navigation
19079		if (!settings.dotsData) {
19080			this._templates = [ $('<div>')
19081				.addClass(settings.dotClass)
19082				.append($('<span>'))
19083				.prop('outerHTML') ];
19084		}
19085
19086		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
19087			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
19088
19089		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
19090			var index = $(e.target).parent().is(this._controls.$absolute)
19091				? $(e.target).index() : $(e.target).parent().index();
19092
19093			e.preventDefault();
19094
19095			this.to(index, settings.dotsSpeed);
19096		}, this));
19097
19098		// override public methods of the carousel
19099		for (override in this._overrides) {
19100			this._core[override] = $.proxy(this[override], this);
19101		}
19102	};
19103
19104	/**
19105	 * Destroys the plugin.
19106	 * @protected
19107	 */
19108	Navigation.prototype.destroy = function() {
19109		var handler, control, property, override;
19110
19111		for (handler in this._handlers) {
19112			this.$element.off(handler, this._handlers[handler]);
19113		}
19114		for (control in this._controls) {
19115			this._controls[control].remove();
19116		}
19117		for (override in this.overides) {
19118			this._core[override] = this._overrides[override];
19119		}
19120		for (property in Object.getOwnPropertyNames(this)) {
19121			typeof this[property] != 'function' && (this[property] = null);
19122		}
19123	};
19124
19125	/**
19126	 * Updates the internal state.
19127	 * @protected
19128	 */
19129	Navigation.prototype.update = function() {
19130		var i, j, k,
19131			lower = this._core.clones().length / 2,
19132			upper = lower + this._core.items().length,
19133			maximum = this._core.maximum(true),
19134			settings = this._core.settings,
19135			size = settings.center || settings.autoWidth || settings.dotsData
19136				? 1 : settings.dotsEach || settings.items;
19137
19138		if (settings.slideBy !== 'page') {
19139			settings.slideBy = Math.min(settings.slideBy, settings.items);
19140		}
19141
19142		if (settings.dots || settings.slideBy == 'page') {
19143			this._pages = [];
19144
19145			for (i = lower, j = 0, k = 0; i < upper; i++) {
19146				if (j >= size || j === 0) {
19147					this._pages.push({
19148						start: Math.min(maximum, i - lower),
19149						end: i - lower + size - 1
19150					});
19151					if (Math.min(maximum, i - lower) === maximum) {
19152						break;
19153					}
19154					j = 0, ++k;
19155				}
19156				j += this._core.mergers(this._core.relative(i));
19157			}
19158		}
19159	};
19160
19161	/**
19162	 * Draws the user interface.
19163	 * @todo The option `dotsData` wont work.
19164	 * @protected
19165	 */
19166	Navigation.prototype.draw = function() {
19167		var difference,
19168			settings = this._core.settings,
19169			disabled = this._core.items().length <= settings.items,
19170			index = this._core.relative(this._core.current()),
19171			loop = settings.loop || settings.rewind;
19172
19173		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
19174
19175		if (settings.nav) {
19176			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
19177			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
19178		}
19179
19180		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
19181
19182		if (settings.dots) {
19183			difference = this._pages.length - this._controls.$absolute.children().length;
19184
19185			if (settings.dotsData && difference !== 0) {
19186				this._controls.$absolute.html(this._templates.join(''));
19187			} else if (difference > 0) {
19188				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
19189			} else if (difference < 0) {
19190				this._controls.$absolute.children().slice(difference).remove();
19191			}
19192
19193			this._controls.$absolute.find('.active').removeClass('active');
19194			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
19195		}
19196	};
19197
19198	/**
19199	 * Extends event data.
19200	 * @protected
19201	 * @param {Event} event - The event object which gets thrown.
19202	 */
19203	Navigation.prototype.onTrigger = function(event) {
19204		var settings = this._core.settings;
19205
19206		event.page = {
19207			index: $.inArray(this.current(), this._pages),
19208			count: this._pages.length,
19209			size: settings && (settings.center || settings.autoWidth || settings.dotsData
19210				? 1 : settings.dotsEach || settings.items)
19211		};
19212	};
19213
19214	/**
19215	 * Gets the current page position of the carousel.
19216	 * @protected
19217	 * @returns {Number}
19218	 */
19219	Navigation.prototype.current = function() {
19220		var current = this._core.relative(this._core.current());
19221		return $.grep(this._pages, $.proxy(function(page, index) {
19222			return page.start <= current && page.end >= current;
19223		}, this)).pop();
19224	};
19225
19226	/**
19227	 * Gets the current succesor/predecessor position.
19228	 * @protected
19229	 * @returns {Number}
19230	 */
19231	Navigation.prototype.getPosition = function(successor) {
19232		var position, length,
19233			settings = this._core.settings;
19234
19235		if (settings.slideBy == 'page') {
19236			position = $.inArray(this.current(), this._pages);
19237			length = this._pages.length;
19238			successor ? ++position : --position;
19239			position = this._pages[((position % length) + length) % length].start;
19240		} else {
19241			position = this._core.relative(this._core.current());
19242			length = this._core.items().length;
19243			successor ? position += settings.slideBy : position -= settings.slideBy;
19244		}
19245
19246		return position;
19247	};
19248
19249	/**
19250	 * Slides to the next item or page.
19251	 * @public
19252	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
19253	 */
19254	Navigation.prototype.next = function(speed) {
19255		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
19256	};
19257
19258	/**
19259	 * Slides to the previous item or page.
19260	 * @public
19261	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
19262	 */
19263	Navigation.prototype.prev = function(speed) {
19264		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
19265	};
19266
19267	/**
19268	 * Slides to the specified item or page.
19269	 * @public
19270	 * @param {Number} position - The position of the item or page.
19271	 * @param {Number} [speed] - The time in milliseconds for the transition.
19272	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
19273	 */
19274	Navigation.prototype.to = function(position, speed, standard) {
19275		var length;
19276
19277		if (!standard) {
19278			length = this._pages.length;
19279			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
19280		} else {
19281			$.proxy(this._overrides.to, this._core)(position, speed);
19282		}
19283	};
19284
19285	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
19286
19287})(window.Zepto || window.jQuery, window, document);
19288
19289/**
19290 * Hash Plugin
19291 * @version 2.0.0-beta.3
19292 * @author Artus Kolanowski
19293 * @license The MIT License (MIT)
19294 */
19295;(function($, window, document, undefined) {
19296	'use strict';
19297
19298	/**
19299	 * Creates the hash plugin.
19300	 * @class The Hash Plugin
19301	 * @param {Owl} carousel - The Owl Carousel
19302	 */
19303	var Hash = function(carousel) {
19304		/**
19305		 * Reference to the core.
19306		 * @protected
19307		 * @type {Owl}
19308		 */
19309		this._core = carousel;
19310
19311		/**
19312		 * Hash index for the items.
19313		 * @protected
19314		 * @type {Object}
19315		 */
19316		this._hashes = {};
19317
19318		/**
19319		 * The carousel element.
19320		 * @type {jQuery}
19321		 */
19322		this.$element = this._core.$element;
19323
19324		/**
19325		 * All event handlers.
19326		 * @protected
19327		 * @type {Object}
19328		 */
19329		this._handlers = {
19330			/*'initialized.owl.carousel': $.proxy(function(e) {
19331				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
19332					$(window).trigger('hashchange.owl.navigation');
19333				}
19334			}, this),*/
19335			'prepared.owl.carousel': $.proxy(function(e) {
19336				if (e.namespace) {
19337					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
19338
19339					if (!hash) {
19340						return;
19341					}
19342
19343					this._hashes[hash] = e.content;
19344				}
19345			}, this),
19346			'changed.owl.carousel': $.proxy(function(e) {
19347				if (e.namespace && e.property.name === 'position') {
19348					var current = this._core.items(this._core.relative(this._core.current())),
19349						hash = $.map(this._hashes, function(item, hash) {
19350							return item === current ? hash : null;
19351						}).join();
19352
19353					if (!hash || window.location.hash.slice(1) === hash) {
19354						return;
19355					}
19356
19357					window.location.hash = hash;
19358				}
19359			}, this)
19360		};
19361
19362		// set default options
19363		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
19364
19365		// register the event handlers
19366		this.$element.on(this._handlers);
19367
19368		// register event listener for hash navigation
19369		/*$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
19370			var hash = window.location.hash.substring(1),
19371				items = this._core.$stage.children(),
19372				position = this._hashes[hash] && items.index(this._hashes[hash]);
19373
19374			if (position === undefined || position === this._core.current()) {
19375				return;
19376			}
19377
19378			this._core.to(this._core.relative(position), false, true);
19379		}, this));*/
19380	};
19381
19382	/**
19383	 * Default options.
19384	 * @public
19385	 */
19386	Hash.Defaults = {
19387		URLhashListener: false
19388	};
19389
19390	/**
19391	 * Destroys the plugin.
19392	 * @public
19393	 */
19394	Hash.prototype.destroy = function() {
19395		var handler, property;
19396
19397		$(window).off('hashchange.owl.navigation');
19398
19399		for (handler in this._handlers) {
19400			this._core.$element.off(handler, this._handlers[handler]);
19401		}
19402		for (property in Object.getOwnPropertyNames(this)) {
19403			typeof this[property] != 'function' && (this[property] = null);
19404		}
19405	};
19406
19407	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
19408
19409})(window.Zepto || window.jQuery, window, document);
19410
19411/**
19412 * Support Plugin
19413 *
19414 * @version 2.0.0-beta.3
19415 * @author Vivid Planet Software GmbH
19416 * @author Artus Kolanowski
19417 * @license The MIT License (MIT)
19418 */
19419;(function($, window, document, undefined) {
19420
19421	var style = $('<support>').get(0).style,
19422		prefixes = 'Webkit Moz O ms'.split(' '),
19423		events = {
19424			transition: {
19425				end: {
19426					WebkitTransition: 'webkitTransitionEnd',
19427					MozTransition: 'transitionend',
19428					OTransition: 'oTransitionEnd',
19429					transition: 'transitionend'
19430				}
19431			},
19432			animation: {
19433				end: {
19434					WebkitAnimation: 'webkitAnimationEnd',
19435					MozAnimation: 'animationend',
19436					OAnimation: 'oAnimationEnd',
19437					animation: 'animationend'
19438				}
19439			}
19440		},
19441		tests = {
19442			csstransforms: function() {
19443				return !!test('transform');
19444			},
19445			csstransforms3d: function() {
19446				return !!test('perspective');
19447			},
19448			csstransitions: function() {
19449				return !!test('transition');
19450			},
19451			cssanimations: function() {
19452				return !!test('animation');
19453			}
19454		};
19455
19456	function test(property, prefixed) {
19457		var result = false,
19458			upper = property.charAt(0).toUpperCase() + property.slice(1);
19459
19460		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
19461			if (style[property] !== undefined) {
19462				result = prefixed ? property : true;
19463				return false;
19464			}
19465		});
19466
19467		return result;
19468	}
19469
19470	function prefixed(property) {
19471		return test(property, true);
19472	}
19473
19474	if (tests.csstransitions()) {
19475		/* jshint -W053 */
19476		$.support.transition = new String(prefixed('transition'))
19477		$.support.transition.end = events.transition.end[ $.support.transition ];
19478	}
19479
19480	if (tests.cssanimations()) {
19481		/* jshint -W053 */
19482		$.support.animation = new String(prefixed('animation'))
19483		$.support.animation.end = events.animation.end[ $.support.animation ];
19484	}
19485
19486	if (tests.csstransforms()) {
19487		/* jshint -W053 */
19488		$.support.transform = new String(prefixed('transform'));
19489		$.support.transform3d = tests.csstransforms3d();
19490	}
19491
19492})(window.Zepto || window.jQuery, window, document);
19493
19494(function(window, document, undefined) {
19495
19496	/**
19497	 * Find the absolute position of an element
19498	 */
19499	var absPos = function(element) {
19500		var offsetLeft, offsetTop;
19501		offsetLeft = offsetTop = 0;
19502		if (element.offsetParent) {
19503			do {
19504				offsetLeft += element.offsetLeft;
19505				offsetTop += element.offsetTop;
19506			} while (element = element.offsetParent);
19507		}
19508		return [offsetLeft, offsetTop];
19509	};
19510
19511	/**
19512	 * @constructor Progress Circle class
19513	 * @param params.canvas Canvas on which the circles will be drawn.
19514	 * @param params.minRadius Inner radius of the innermost circle, in px.
19515	 * @param params.arcWidth Width of each circle(to be more accurate, ring).
19516	 * @param params.gapWidth Space between each circle.
19517	 * @param params.centerX X coordinate of the center of circles.
19518	 * @param params.centerY Y coordinate of the center of circles.
19519	 * @param params.infoLineBaseAngle Base angle of the info line.
19520	 * @param params.infoLineAngleInterval Angles between the info lines.
19521	 */
19522	var ProgressCircle = function(params) {
19523		this.canvas = params.canvas;
19524		this.minRadius = params.minRadius || 15;
19525		this.arcWidth = params.arcWidth || 5;
19526		this.gapWidth = params.gapWidth || 3;
19527		this.centerX = params.centerX || this.canvas.width / 2;
19528		this.centerY = params.centerY || this.canvas.height / 2;
19529		this.infoLineLength = params.infoLineLength || 60;
19530		this.horizLineLength = params.horizLineLength || 10;
19531		this.infoLineAngleInterval = params.infoLineAngleInterval || Math.PI / 8;
19532		this.infoLineBaseAngle = params.infoLineBaseAngle || Math.PI / 6;
19533
19534		this.context = this.canvas.getContext('2d');
19535
19536		this.width = this.canvas.width;
19537		this.height = this.canvas.height;
19538
19539		this.circles = [];
19540		this.runningCount = 0;
19541	};
19542
19543	ProgressCircle.prototype = {
19544		constructor: ProgressCircle,
19545
19546		/**
19547		 * @method Adds an progress monitor entry.
19548		 * @param params.fillColor Color to fill in the circle.
19549		 * @param params.outlineColor Color to outline the circle.
19550		 * @param params.progressListener Callback function to fetch the progress.
19551		 * @param params.infoListener Callback function to fetch the info.
19552		 * @returns this
19553		 */
19554		addEntry: function(params) {
19555			this.circles.push(new Circle({
19556				canvas: this.canvas,
19557				context: this.context,
19558				centerX: this.centerX,
19559				centerY: this.centerY,
19560				innerRadius: this.minRadius + this.circles.length *
19561					(this.gapWidth + this.arcWidth),
19562				arcWidth: this.arcWidth,
19563				infoLineLength: this.infoLineLength,
19564				horizLineLength: this.horizLineLength,
19565
19566				id: this.circles.length,
19567				fillColor: params.fillColor,
19568				outlineColor: params.outlineColor,
19569				progressListener: params.progressListener,
19570				infoListener: params.infoListener,
19571				infoLineAngle: this.infoLineBaseAngle +
19572					this.circles.length * this.infoLineAngleInterval,
19573			}));
19574
19575			return this;
19576		},
19577
19578		/**
19579		 * @method Starts the monitor and updates with the given interval.
19580		 * @param interval Interval between updates, in millisecond.
19581		 * @returns this
19582		 */
19583		start: function(interval) {
19584			var self = this;
19585			this.timer = setInterval(function() {
19586				self._update();
19587			}, interval || 33);
19588
19589			return this;
19590		},
19591
19592		/**
19593		 * @method Stop the animation.
19594		 */
19595		stop: function() {
19596			clearTimeout(this.timer);
19597		},
19598
19599		/**
19600		 * @private
19601		 * @method Call update on each circle and redraw them.
19602		 * @returns this
19603		 */
19604		_update: function() {
19605			this._clear();
19606			this.circles.forEach(function(circle, idx, array) {
19607				circle.update();
19608			});
19609
19610			return this;
19611		},
19612
19613		/**
19614		 * @private
19615		 * @method Clear the canvas.
19616		 * @returns this
19617		 */
19618		_clear: function() {
19619			this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
19620
19621			return this;
19622		},
19623
19624	};
19625
19626	/**
19627	 * @private
19628	 * @class Individual progress circle.
19629	 * @param params.canvas Canvas on which the circle will be drawn.
19630	 * @param params.context Context of the canvas.
19631	 * @param params.innerRadius Inner radius of the circle, in px.
19632	 * @param params.arcWidth Width of each arc(circle).
19633	 * @param params.gapWidth Distance between each arc.
19634	 * @param params.centerX X coordinate of the center of circles.
19635	 * @param params.centerY Y coordinate of the center of circles.
19636	 * @param params.fillColor Color to fill in the circle.
19637	 * @param params.outlineColor Color to outline the circle.
19638	 * @param params.progressListener Callback function to fetch the progress.
19639	 * @param params.infoListener Callback function to fetch the info.
19640	 * @param params.infoLineAngle Angle of info line.
19641	 */
19642	var Circle = function(params) {
19643		this.id = params.id;
19644		this.canvas = params.canvas;
19645		this.context = params.context;
19646		this.centerX = params.centerX;
19647		this.centerY = params.centerY;
19648		this.arcWidth = params.arcWidth;
19649		this.innerRadius = params.innerRadius || 0;
19650		this.fillColor = params.fillColor || '#fff';
19651		this.outlineColor = params.outlineColor || this.fillColor;
19652		this.progressListener = params.progressListener;
19653		this.infoLineLength = params.infoLineLength || 250;
19654		this.horizLineLength = params.horizLineLength || 50;
19655		this.infoListener = params.infoListener;
19656		this.infoLineAngle = params.infoLineAngle;
19657
19658		this.outerRadius = this.innerRadius + this.arcWidth;
19659
19660		// If the info listener is not registered, then don't calculate
19661		// the related coordinates
19662		if (!this.infoListener) return;
19663
19664		// calculate the info-line turning points
19665		var angle = this.infoLineAngle,
19666			arcDistance = (this.innerRadius + this.outerRadius) / 2,
19667
19668			sinA = Math.sin(angle),
19669			cosA = Math.cos(angle);
19670
19671		this.infoLineStartX = this.centerX + sinA * arcDistance;
19672		this.infoLineStartY = this.centerY - cosA * arcDistance;
19673
19674		this.infoLineMidX = this.centerX + sinA * this.infoLineLength;
19675		this.infoLineMidY = this.centerY - cosA * this.infoLineLength;
19676
19677		this.infoLineEndX = this.infoLineMidX +
19678			 (sinA < 0 ? -this.horizLineLength : this.horizLineLength);
19679		this.infoLineEndY = this.infoLineMidY;
19680
19681		var infoText = document.createElement('div'),
19682			style = infoText.style;
19683
19684		style.color = this.fillColor;
19685		style.position = 'absolute';
19686		style.left = this.infoLineEndX + absPos(this.canvas)[0] + 'px';
19687		// style.top will be calculated in the `drawInfo` method. Since
19688		// user may want to change the size of the font, so the top offset
19689		// must be updated in each loop.
19690		infoText.className = 'ProgressCircleInfo'; // For css styling
19691		infoText.id = 'progress_circle_info_' + this.id;
19692		document.body.appendChild(infoText);
19693		this.infoText = infoText;
19694	};
19695
19696	Circle.prototype = {
19697		constructor: Circle,
19698
19699		update: function() {
19700			this.progress = this.progressListener();
19701			this._draw();
19702
19703			if (this.infoListener) {
19704				this.info = this.infoListener();
19705				this._drawInfo();
19706			}
19707		},
19708
19709		/**
19710		 * @private
19711		 * @method Draw the circle on the canvas.
19712		 * @returns this
19713		 */
19714		_draw: function() {
19715			var ctx = this.context,
19716
19717				ANGLE_OFFSET = -Math.PI / 2,
19718
19719				startAngle = 0 + ANGLE_OFFSET,
19720				endAngle= startAngle + this.progress * Math.PI * 2,
19721
19722				x = this.centerX,
19723				y = this.centerY,
19724
19725				innerRadius = this.innerRadius - this.arcWidth - 1,
19726				outerRadius = this.outerRadius - this.arcWidth - 1;
19727
19728			if ( innerRadius < 0 )
19729				return;
19730
19731			ctx.fillStyle = this.fillColor;
19732			ctx.strokeStyle = this.outlineColor;
19733
19734			ctx.beginPath();
19735			ctx.arc(x, y, innerRadius, startAngle, endAngle, false);
19736			ctx.arc(x, y, outerRadius, endAngle, startAngle, true);
19737			ctx.closePath();
19738			ctx.stroke();
19739			ctx.fill();
19740
19741			return this;
19742		},
19743
19744		/**
19745		 * @private
19746		 * @method Draw the info lines and info text.
19747		 * @returns this
19748		 */
19749		_drawInfo: function() {
19750
19751			var pointList, lineHeight;
19752
19753			pointList = [
19754				[this.infoLineStartX, this.infoLineStartY],
19755				[this.infoLineMidX, this.infoLineMidY],
19756				[this.infoLineEndX, this.infoLineEndY],
19757			];
19758			this._drawSegments(pointList, false);
19759
19760			this.infoText.innerHTML = this.info;
19761
19762			lineHeight = this.infoText.offsetHeight;
19763			this.infoText.style.top = this.infoLineEndY +
19764				absPos(this.canvas)[1] - lineHeight / 2 + 'px';
19765
19766			return this;
19767		},
19768
19769		/**
19770		 * @private
19771		 * @method Helper function to draw the segments
19772		 * @param pointList An array of points in the form of [x, y].
19773		 * @param close Whether to connect the first and last point.
19774		 */
19775		_drawSegments: function(pointList, close) {
19776			var ctx = this.context;
19777
19778			ctx.beginPath();
19779			ctx.moveTo(pointList[0][0], pointList[0][1]);
19780			for (var i = 1; i < pointList.length; ++i) {
19781				ctx.lineTo(pointList[i][0], pointList[i][1]);
19782			}
19783
19784			if (close) {
19785				ctx.closePath();
19786			}
19787			ctx.stroke();
19788		},
19789	};
19790
19791	window.ProgressCircle = ProgressCircle;
19792
19793})(window, document);
19794
19795
19796
19797
19798/* =========================================================
19799 * jquery.vc_chart.js v1.0
19800 * =========================================================
19801 * Copyright 2013 Wpbakery
19802 *
19803 * Jquery chart plugin for the Visual Composer.
19804 * ========================================================= */
19805(function($){
19806	/**
19807	 * Pie chart animated.
19808	 * @param element - DOM element
19809	 * @param options - settings object.
19810	 * @constructor
19811	 */
19812	var VcChart = function(element, options) {
19813		this.el = element;
19814		this.$el = $(this.el);
19815		var $this = this;
19816		$this.options = $.extend({
19817			color: 'wpb_button',
19818			units: '',
19819			width: '',
19820			label_selector: '.vc_pie_chart_value',
19821			back_selector: '.vc_pie_chart_back',
19822			responsive: true
19823		}, options);
19824		$this.init();
19825	};
19826	VcChart.prototype = {
19827		constructor: VcChart,
19828		_progress_v: 0,
19829		animated: false,
19830		colors: {
19831			'wpb_button': 'rgba(247, 247, 247, 1)',
19832			'btn-primary': 'rgba(0, 136, 204, 1)',
19833			'btn-info': 'rgba(88, 185, 218, 1)',
19834			'btn-success': 'rgba(106, 177, 101, 1)',
19835			'btn-warning': 'rgba(255, 153, 0, 1)',
19836			'btn-danger': 'rgba(255, 103, 91, 1)',
19837			'btn-inverse': 'rgba(85, 85, 85, 1)'
19838		},
19839		init: function() {
19840			this.setupColor();
19841			this.value = this.$el.data('pie-value')/100;
19842			this.label_value = this.$el.data('pie-label-value') || this.$el.data('pie-value');
19843			this.$wrapper = $('.vc_pie_wrapper', this.$el);
19844			this.$label = $(this.options.label_selector, this.$el);
19845			this.$back = $(this.options.back_selector, this.$el);
19846			this.$canvas = this.$el.find('canvas');
19847			this.arcWidth = this.$el.data('pie-width') * 2;
19848			this.draw();
19849			this.setWayPoint();
19850			if(this.options.responsive === true) this.setResponsive();
19851			if (UNCODE.isMobile) this._progress_v = this.value;
19852		},
19853		setupColor: function() {
19854			// if(typeof this.colors[this.options.color] !== 'undefined') {
19855			//     this.color = this.colors[this.options.color];
19856			// } else if(typeof this.options.color === 'string' && this.options.color.match(/^rgba?\([^\)]+\)/)) {
19857			//     this.color = this.options.color;
19858			// } else {
19859			//     this.color = 'rgba(247, 247, 247, 0.2)';
19860			// }
19861			if(typeof this.options.color !== 'undefined') {
19862				this.color = this.options.color;
19863			} else this.color = 'rgba(247, 247, 247, 0.2)';
19864
19865		},
19866		setResponsive: function() {
19867			var that = this;
19868			if (!UNCODE.isMobile) {
19869				$(window).resize(function(){
19870					if(that.animated === true) that.circle.stop();
19871					that.draw(true);
19872				});
19873			}
19874		},
19875		draw: function(redraw) {
19876			var w = this.$el.addClass('vc_ready').width() * 2,
19877				border_w = this.arcWidth,
19878				radius;
19879			if(!w) w = this.$el.parents(':visible').first().width()-2;
19880			//w = Math.round(w/100*80);
19881			//if (w < 250) w = 250;
19882			radius = w/2;
19883			this.$wrapper.css({"width" : (w / 2) + "px"});
19884			this.$label.css({"width" : (w / 2), "height" : (w / 2), "line-height" : (w / 2)+"px"});
19885			this.$back.css({"width" : (w / 2), "height" : (w / 2)});
19886			this.$canvas.attr({"width" : w + "px", "height" : w + "px"});
19887			this.$el.addClass('vc_ready');
19888			this.circle = new ProgressCircle({
19889				canvas: this.$canvas.get(0),
19890				minRadius: radius,
19891				arcWidth: border_w
19892			});
19893			if(redraw === true && this.animated === true) {
19894				this._progress_v = this.value;
19895				this.circle.addEntry({
19896					fillColor: this.color,
19897					progressListener: $.proxy(this.setProgress, this)
19898				}).start();
19899			}
19900		},
19901		setProgress: function() {
19902			if (this._progress_v >= this.value) {
19903				this.circle.stop();
19904				this.animated = true;
19905				this.$label.html(this.label_value + this.options.units);
19906				return this._progress_v;
19907			}
19908			this._progress_v += 0.01;
19909			if (!isNaN(this.label_value)) {
19910				var label_value = this._progress_v/this.value*this.label_value;
19911				var val = Math.round(label_value) + this.options.units;
19912				this.$label.html(val);
19913			} else this.$label.html(this.label_value + this.options.units);
19914			return this._progress_v;
19915		},
19916		animate: function() {
19917			if(this.animated !== true) {
19918				this.circle.addEntry({
19919					fillColor: this.color,
19920					progressListener: $.proxy(this.setProgress, this)
19921				}).start(10);
19922			}
19923		},
19924		setWayPoint: function() {
19925			if (typeof $.fn.waypoint !== 'undefined' && !UNCODE.isMobile) {
19926				this.$el.waypoint($.proxy(this.animate, this), { offset: '85%' });
19927			} else {
19928				this.animate();
19929			}
19930		}
19931	};
19932	/**
19933	 * jQuery plugin
19934	 * @param option - object with settings
19935	 * @return {*}
19936	 */
19937	$.fn.vcChat = function(option, value) {
19938		return this.each(function () {
19939			var $this = $(this),
19940				data = $this.data('vc_chart'),
19941				options = typeof option === 'object' ? option : {
19942					color: $this.data('pie-color'),
19943					units: $this.data('pie-units')
19944				};
19945			if (typeof option == 'undefined') $this.data('vc_chart', (data = new VcChart(this, options)));
19946			if (typeof option == 'string') data[option](value);
19947		});
19948	};
19949	/**
19950	 * Allows users to rewrite function inside theme.
19951	 */
19952	if ( typeof window['vc_pieChart'] !== 'function' ) {
19953		window.vc_pieChart = function() {
19954			$('.vc_pie_chart:visible:not(.vc_ready)').vcChat();
19955		}
19956	}
19957	$(document).ready(function(){
19958		!window.vc_iframe && vc_pieChart();
19959
19960		/**
19961		* Tab and collapse integration.
19962		*/
19963		$('.nav-tabs a').on('shown.bs.tab', function(e){
19964			var $cont = $(e.target).closest('.tab-container'),
19965				$active = $('.tab-pane.active', $cont);
19966			$('.vc_pie_chart:not(.vc_ready)', $active).vcChat();
19967		});
19968
19969		$('.panel-collapse').on('shown.bs.collapse', function (e) {
19970			$('.vc_pie_chart:not(.vc_ready)', e.target).vcChat();
19971		})
19972	});
19973
19974})(window.jQuery);
19975
19976/* Progress bar
19977 ---------------------------------------------------------- */
19978function uncode_progress_bar() {
19979	jQuery.each(jQuery('.vc_progress_bar'), function(index, val) {
19980		if (UNCODE.isUnmodalOpen && !val.closest('#unmodal-content')) {
19981			return;
19982		}
19983		if (!UNCODE.isMobile) {
19984			new Waypoint({
19985				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
19986				element: val,
19987				handler: function() {
19988					var element = jQuery(this.element);
19989					element.find('.vc_single_bar').each(function(index) {
19990						var $this = jQuery(this),
19991							bar = $this.find('.vc_bar'),
19992							val = bar.data('percentage-value');
19993						setTimeout(function() {
19994							bar.css({
19995								"width": val + '%'
19996							});
19997						}, index * 200);
19998					});
19999				},
20000				offset: '80%'
20001			});
20002		} else {
20003			var element = jQuery(val);
20004			element.find('.vc_single_bar').each(function(index) {
20005				var $this = jQuery(this),
20006					bar = $this.find('.vc_bar'),
20007					val = bar.data('percentage-value');
20008				setTimeout(function() {
20009					bar.css({
20010						"width": val + '%'
20011					});
20012				}, index * 200);
20013			});
20014		}
20015	});
20016};
20017uncode_progress_bar();
20018
20019/*!
20020 * jquery.counterup.js 1.0
20021 *
20022 * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal
20023 * Released under the GPL v2 License
20024 *
20025 * Date: Nov 26, 2013
20026 */
20027(function($) {
20028	"use strict";
20029	$.fn.counterUp = function(options) {
20030		// Defaults
20031		var settings = $.extend({
20032			'time': 400,
20033			'delay': 10
20034		}, options);
20035		return this.each(function() {
20036			// Store the object
20037			var $this = $(this);
20038			var $settings = settings;
20039			var counterUpper = function() {
20040				var nums = [];
20041				var divisions = $settings.time / $settings.delay;
20042				var numReal = $this.attr('data-val'),
20043				num = numReal;
20044				var isComma = /[0-9]+,[0-9]+/.test(num);
20045				num = num.replace(/,/g, '');
20046				var isInt = /^[0-9]+$/.test(num);
20047				var isFloat = /^[0-9]+\.[0-9]+$/.test(num);
20048				var decimalPlaces = isFloat ? (num.split('.')[1] || []).length : 0;
20049				// Generate list of incremental numbers to display
20050				for (var i = divisions; i >= 1; i--) {
20051					// Preserve as int if input was int
20052					var newNum = parseInt(num / divisions * i);
20053					// Preserve float if input was float
20054					if (isFloat) {
20055						newNum = parseFloat(num / divisions * i).toFixed(decimalPlaces);
20056					}
20057					// Preserve commas if input had commas
20058					if (isComma) {
20059						while (/(\d+)(\d{3})/.test(newNum.toString())) {
20060							newNum = newNum.toString().replace(/(\d+)(\d{3})/, '$1' + ',' + '$2');
20061						}
20062					}
20063					nums.unshift(newNum);
20064				}
20065				nums.push(numReal);
20066				$this.data('counterup-nums', nums);
20067				$this.text('0');
20068				// Updates the number until we're done
20069				var f = function() {
20070					if ($this.data('counterup-nums') != null) {
20071						$this.text($this.data('counterup-nums').shift());
20072						if ($this.data('counterup-nums').length) {
20073							setTimeout($this.data('counterup-func'), $settings.delay);
20074						} else {
20075							delete $this.data('counterup-nums');
20076							$this.data('counterup-nums', null);
20077							$this.data('counterup-func', null);
20078						}
20079					}
20080				};
20081				$this.data('counterup-func', f);
20082				// Start the count up
20083				setTimeout($this.data('counterup-func'), $settings.delay);
20084			};
20085			// Perform counts when the element gets into view
20086			new Waypoint({
20087				context: UNCODE.isUnmodalOpen ? document.getElementById('unmodal-content') : window,
20088				element: this,
20089				handler: function() {
20090					counterUpper();
20091					if (!UNCODE.isUnmodalOpen) {
20092						this.destroy();
20093					}
20094				},
20095				offset: '100%'
20096			});
20097		});
20098	};
20099})(jQuery);
20100
20101/*!
20102 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
20103 * Copyright (c) 2016 Edson Hilios
20104 *
20105 * Permission is hereby granted, free of charge, to any person obtaining a copy of
20106 * this software and associated documentation files (the "Software"), to deal in
20107 * the Software without restriction, including without limitation the rights to
20108 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
20109 * the Software, and to permit persons to whom the Software is furnished to do so,
20110 * subject to the following conditions:
20111 *
20112 * The above copyright notice and this permission notice shall be included in all
20113 * copies or substantial portions of the Software.
20114 *
20115 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20116 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20117 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20118 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20119 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20120 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20121 */
20122(function(factory) {
20123	"use strict";
20124	if (typeof define === "function" && define.amd) {
20125		define([ "jquery" ], factory);
20126	} else {
20127		factory(jQuery);
20128	}
20129})(function($) {
20130	"use strict";
20131	var instances = [], matchers = [], defaultOptions = {
20132		precision: 100,
20133		elapse: false,
20134		defer: false
20135	};
20136	matchers.push(/^[0-9]*$/.source);
20137	matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
20138	matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
20139	matchers = new RegExp(matchers.join("|"));
20140	function parseDateString(dateString) {
20141		if (dateString instanceof Date) {
20142			return dateString;
20143		}
20144		if (String(dateString).match(matchers)) {
20145			if (String(dateString).match(/^[0-9]*$/)) {
20146				dateString = Number(dateString);
20147			}
20148			if (String(dateString).match(/\-/)) {
20149				dateString = String(dateString).replace(/\-/g, "/");
20150			}
20151			return new Date(dateString);
20152		} else {
20153			throw new Error("Couldn't cast `" + dateString + "` to a date object.");
20154		}
20155	}
20156	var DIRECTIVE_KEY_MAP = {
20157		Y: "years",
20158		m: "months",
20159		n: "daysToMonth",
20160		d: "daysToWeek",
20161		w: "weeks",
20162		W: "weeksToMonth",
20163		H: "hours",
20164		M: "minutes",
20165		S: "seconds",
20166		D: "totalDays",
20167		I: "totalHours",
20168		N: "totalMinutes",
20169		T: "totalSeconds"
20170	};
20171	function escapedRegExp(str) {
20172		var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
20173		return new RegExp(sanitize);
20174	}
20175	function strftime(offsetObject) {
20176		return function(format) {
20177			var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
20178			if (directives) {
20179				for (var i = 0, len = directives.length; i < len; ++i) {
20180					var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
20181					directive = directive[2];
20182					if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
20183						value = DIRECTIVE_KEY_MAP[directive];
20184						value = Number(offsetObject[value]);
20185					}
20186					if (value !== null) {
20187						if (modifier === "!") {
20188							value = pluralize(plural, value);
20189						}
20190						if (modifier === "") {
20191							if (value < 10) {
20192								value = "0" + value.toString();
20193							}
20194						}
20195						format = format.replace(regexp, value.toString());
20196					}
20197				}
20198			}
20199			format = format.replace(/%%/, "%");
20200			return format;
20201		};
20202	}
20203	function pluralize(format, count) {
20204		var plural = "s", singular = "";
20205		if (format) {
20206			format = format.rep
vendor: 8,618 bytes, lines 20206-20350
20206lace(/(:|;|\s)/gi, "").split(/\,/);
20207			if (format.length === 1) {
20208				plural = format[0];
20209			} else {
20210				singular = format[0];
20211				plural = format[1];
20212			}
20213		}
20214		if (Math.abs(count) > 1) {
20215			return plural;
20216		} else {
20217			return singular;
20218		}
20219	}
20220	var Countdown = function(el, finalDate, options) {
20221		this.el = el;
20222		this.$el = $(el);
20223		this.interval = null;
20224		this.offset = {};
20225		this.options = $.extend({}, defaultOptions);
20226		this.instanceNumber = instances.length;
20227		instances.push(this);
20228		this.$el.data("countdown-instance", this.instanceNumber);
20229		if (options) {
20230			if (typeof options === "function") {
20231				this.$el.on("update.countdown", options);
20232				this.$el.on("stoped.countdown", options);
20233				this.$el.on("finish.countdown", options);
20234			} else {
20235				this.options = $.extend({}, defaultOptions, options);
20236			}
20237		}
20238		this.setFinalDate(finalDate);
20239		if (this.options.defer === false) {
20240			this.start();
20241		}
20242	};
20243	$.extend(Countdown.prototype, {
20244		start: function() {
20245			if (this.interval !== null) {
20246				clearInterval(this.interval);
20247			}
20248			var self = this;
20249			this.update();
20250			this.interval = setInterval(function() {
20251				self.update.call(self);
20252			}, this.options.precision);
20253		},
20254		stop: function() {
20255			clearInterval(this.interval);
20256			this.interval = null;
20257			this.dispatchEvent("stoped");
20258		},
20259		toggle: function() {
20260			if (this.interval) {
20261				this.stop();
20262			} else {
20263				this.start();
20264			}
20265		},
20266		pause: function() {
20267			this.stop();
20268		},
20269		resume: function() {
20270			this.start();
20271		},
20272		remove: function() {
20273			this.stop.call(this);
20274			instances[this.instanceNumber] = null;
20275			delete this.$el.data().countdownInstance;
20276		},
20277		setFinalDate: function(value) {
20278			this.finalDate = parseDateString(value);
20279		},
20280		update: function() {
20281			if (this.$el.closest("html").length === 0) {
20282				this.remove();
20283				return;
20284			}
20285			var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
20286			newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
20287			newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
20288			newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
20289			if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
20290				return;
20291			} else {
20292				this.totalSecsLeft = newTotalSecsLeft;
20293			}
20294			this.elapsed = now >= this.finalDate;
20295			this.offset = {
20296				seconds: this.totalSecsLeft % 60,
20297				minutes: Math.floor(this.totalSecsLeft / 60) % 60,
20298				hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
20299				days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
20300				daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
20301				daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
20302				weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
20303				weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
20304				months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
20305				years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
20306				totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
20307				totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
20308				totalMinutes: Math.floor(this.totalSecsLeft / 60),
20309				totalSeconds: this.totalSecsLeft
20310			};
20311			if (!this.options.elapse && this.totalSecsLeft === 0) {
20312				this.stop();
20313				this.dispatchEvent("finish");
20314			} else {
20315				this.dispatchEvent("update");
20316			}
20317		},
20318		dispatchEvent: function(eventName) {
20319			var event = $.Event(eventName + ".countdown");
20320			event.finalDate = this.finalDate;
20321			event.elapsed = this.elapsed;
20322			event.offset = $.extend({}, this.offset);
20323			event.strftime = strftime(this.offset);
20324			this.$el.trigger(event);
20325		}
20326	});
20327	$.fn.countdown = function() {
20328		var argumentsArray = Array.prototype.slice.call(arguments, 0);
20329		return this.each(function() {
20330			var instanceNumber = $(this).data("countdown-instance");
20331			if (instanceNumber !== undefined) {
20332				var instance = instances[instanceNumber], method = argumentsArray[0];
20333				if (Countdown.prototype.hasOwnProperty(method)) {
20334					instance[method].apply(instance, argumentsArray.slice(1));
20335				} else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
20336					instance.setFinalDate.call(instance, method);
20337					instance.start();
20338				} else {
20339					$.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
20340				}
20341			} else {
20342				new Countdown(this, argumentsArray[0], argumentsArray[1]);
20343			}
20344		});
20345	};
20346});
20347
20348!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;
20349function getStyles(config){
20350  // 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;
20350left: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+"}"
20351};
20352  var ShareUtils;
20353
20354if ((!("classList" in document.documentElement)) && Object.defineProperty && typeof HTMLElement !== "undefined") {
20355  Object.defineProperty(HTMLElement.prototype, "classList", {
20356    get: function() {
20357      var ret, self, update;
20358      update = function(fn) {
20359        return function(value) {
20360          var classes, index;
20361          classes = self.className.split(/\s+/);
20362          index = classes.indexOf(value);
20363          fn(classes, index, value);
20364          self.className = classes.join(" ");
20365        };
20366      };
20367      self = this;
20368      ret = {
20369        add: update(function(classes, index, value) {
20370          ~index || classes.push(value);
20371        }),
20372        remove: update(function(classes, index) {
20373          ~index && classes.splice(index, 1);
20374        }),
20375        toggle: update(function(classes, index, value) {
20376          if (~index) {
20377            classes.splice(index, 1);
20378          } else {
20379            classes.push(value);
20380          }
20381        }),
20382        contains: function(value) {
20383          return !!~self.className.split(/\s+/).indexOf(value);
20384        },
20385        item: function(i) {
20386          return self.className.split(/\s+/)[i] || null;
20387        }
20388      };
20389      Object.defineProperty(ret, "length", {
20390        get: function() {
20391          return self.className.split(/\s+/).length;
20392        }
20393      });
20394      return ret;
20395    }
20396  });
20397}
20398
20399String.prototype.to_rfc3986 = function() {
20400  var tmp;
20401  tmp = encodeURIComponent(this);
20402  return tmp.replace(/[!'()*]/g, function(c) {
20403    return "%" + c.charCodeAt(0).toString(16);
20404  });
20405};
20406
20407ShareUtils = (function() {
20408  function ShareUtils() {}
20409
20410  ShareUtils.prototype.extend = function(to, from, overwrite) {
20411    var hasProp, prop;
20412    for (prop in from) {
20413      hasProp = to[prop] !== undefined;
20414      if (hasProp && typeof from[prop] === "object") {
20415        this.extend(to[prop], from[prop], overwrite);
20416      } else {
20417        if (overwrite || !hasProp) {
20418          to[prop] = from[prop];
20419        }
20420      }
20421    }
20422  };
20423
20424  ShareUtils.prototype.hide = function(el) {
20425    return el.style.display = "none";
20426  };
20427
20428  ShareUtils.prototype.show = function(el) {
20429    return el.style.display = "block";
20430  };
20431
20432  ShareUtils.prototype.has_class = function(el, class_name) {
20433    return el.classList.contains(class_name);
20434  };
20435
20436  ShareUtils.prototype.add_class = function(el, class_name) {
20437    return el.classList.add(class_name);
20438  };
20439
20440  ShareUtils.prototype.remove_class = function(el, class_name) {
20441    return el.classList.remove(class_name);
20442  };
20443
20444  ShareUtils.prototype.is_encoded = function(str) {
20445    str = str.to_rfc3986();
20446    return decodeURIComponent(str) !== str;
20447  };
20448
20449  ShareUtils.prototype.encode = function(str) {
20450    if (typeof str === "undefined" || this.is_encoded(str)) {
20451      return str;
20452    } else {
20453      return str.to_rfc3986();
20454    }
20455  };
20456
20457  ShareUtils.prototype.popup = function(url, params) {
20458    var k, popup, qs, v;
20459    if (params == null) {
20460      params = {};
20461    }
20462    popup = {
20463      width: 500,
20464      height: 350
20465    };
20466    popup.top = (screen.height / 2) - (popup.height / 2);
20467    popup.left = (screen.width / 2) - (popup.width / 2);
20468    qs = ((function() {
20469      var _results;
20470      _results = [];
20471      for (k in params) {
20472        v = params[k];
20473        _results.push("" + k + "=" + (this.encode(v)));
20474      }
20475      return _results;
20476    }).call(this)).join('&');
20477    if (qs) {
20478      qs = "?" + qs;
20479    }
20480    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=" 
20480+ popup.width + ",height=" + popup.height);
20481  };
20482
20483  return ShareUtils;
20484
20485})();
20486var Share,
20487  __hasProp = {}.hasOwnProperty,
20488  __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; };
20489
20490Share = (function(_super) {
20491  __extends(Share, _super);
20492
20493  function Share(element, options) {
20494    this.element = element;
20495    this.el = {
20496      head: document.getElementsByTagName('head')[0],
20497      body: document.getElementsByTagName('body')[0]
20498    };
20499    this.config = {
20500      enabled_networks: 0,
20501      protocol: ['http', 'https'].indexOf(window.location.href.split(':')[0]) === -1 ? 'https://' : '//',
20502      url: window.location.href.replace("&", "%26"),
20503      caption: null,
20504      title: this.default_title(),
20505      image: this.default_image(),
20506      description: this.default_description(),
20507      ui: {
20508        flyout: 'top center',
20509        button_text: 'Share',
20510        button_font: true,
20511        icon_font: true
20512      },
20513      networks: {
20514        twitter: {
20515          enabled: true,
20516          url: null,
20517          title: null,
20518          description: null
20519        },
20520        facebook: {
20521          enabled: true,
20522          load_sdk: true,
20523          url: null,
20524          app_id: null,
20525          title: null,
20526          caption: null,
20527          description: null,
20528          image: null
20529        },
20530        pinterest: {
20531          enabled: true,
20532          url: null,
20533          image: null,
20534          description: null
20535        },
20536        reddit: {
20537          enabled: true,
20538          url: null,
20539          title: null
20540        },
20541        linkedin: {
20542          enabled: true,
20543          url: null,
20544          title: null,
20545          description: null
20546        },
20547        xing: {
20548          enabled: true,
20549          url: null,
20550          title: null,
20551          image: null,
20552          description: null
20553        },
20554        whatsapp: {
20555          enabled: true,
20556          description: null,
20557          url: null
20558        },
20559        email: {
20560          enabled: true,
20561          title: null,
20562          description: null,
20563          url: null
20564        }
20565      }
20566    };
20567    this.setup(element, options);
20568    return this;
20569  }
20570
20571  Share.prototype.setup = function(element, opts) {
20572    var index, instance, instances, _i, _len;
20573    instances = document.querySelectorAll(element);
20574    this.extend(this.config, opts, true);
20575    this.set_global_configuration();
20576    this.normalize_network_configuration();
20577    if (this.config.ui.icon_font) {
20578      this.inject_icons();
20579    }
20580    if (this.config.ui.button_font) {
20581      this.inject_fonts();
20582    }
20583    if (this.config.networks.facebook.enabled && this.config.networks.facebook.load_sdk) {
20584      this.inject_facebook_sdk();
20585    }
20586    for (index = _i = 0, _len = instances.length; _i < _len; index = ++_i) {
20587      instance = instances[index];
20588      this.setup_instance(element, index);
20589    }
20590  };
20591
20592  Share.prototype.setup_instance = function(element, index) {
20593    var button, instance, label, network, networks, _i, _len, _results,
20594      _this = this;
20595    instance = document.querySelectorAll(element)[index];
20596    this.hide(instance);
20597    this.add_class(instance, "sharer-" + index);
20598    instance = document.querySelectorAll(element)[index];
20599    this.inject_css(instance);
20600    this.inject_html(instance);
20601    this.show(instance);
20602    label = instance.getElementsByTagName("label")[0];
20603    button = instance.getElementsByClassName("social")[0];
20604    networks = instance.getElementsByTagName('li');
20605    this.add_class(button, "networks-" + this.config.enabled_networks);
20606    label.addEventListener("click", function() {
20607      return _this.event_toggle(button);
20608    });
20609    _this = this;
20610    _results = [];
20611    for (index = _i = 0, _len = networks.length; _i < _len; index = ++_i) {
20612      network = networks[index];
20613      _results.push(network.addEventListener("click", function() {
20614        _this.event_network(instance, this);
20615        return _this.event_close(button);
20616      }));
20617    }
20618    return _results;
20619  };
20620
20621  Share.prototype.event_toggle = function(button) {
20622    if (this.has_class(button, "active")) {
20623      return this.event_close(button);
20624    } else {
20625      return this.event_open(button);
20626    }
20627  };
20628
20629  Share.prototype.event_open = function(button) {
20630    if (this.has_class(button, "load")) {
20631      this.remove_class(button, "load");
20632    }
20633    return this.add_class(button, "active");
20634  };
20635
20636  Share.prototype.event_close = function(button) {
20637    return this.remove_class(button, "active");
20638  };
20639
20640  Share.prototype.event_network = function(instance, network) {
20641    var name;
20642    name = network.getAttribute("data-network");
20643    this.hook("before", name, instance);
20644    this["network_" + name]();
20645    return this.hook("after", name, instance);
20646  };
20647
20648  Share.prototype.open = function() {
20649    return this["public"]("open");
20650  };
20651
20652  Share.prototype.close = function() {
20653    return this["public"]("close");
20654  };
20655
20656  Share.prototype.toggle = function() {
20657    return this["public"]("toggle");
20658  };
20659
20660  Share.prototype["public"] = function(action) {
20661    var button, index, instance, _i, _len, _ref, _results;
20662    _ref = document.querySelectorAll(this.element);
20663    _results = [];
20664    for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
20665      instance = _ref[index];
20666      button = instance.getElementsByClassName("social")[0];
20667      _results.push(this["event_" + action](button));
20668    }
20669    return _results;
20670  };
20671
20672  Share.prototype.network_facebook = function() {
20673    if (this.config.networks.facebook.load_sdk) {
20674      if (!window.FB) {
20675        return console.error("The Facebook JS SDK hasn't loaded yet.");
20676      }
20677      return FB.ui({
20678        method: 'feed',
20679        name: this.config.networks.facebook.title,
20680        link: this.config.networks.facebook.url,
20681        picture: this.config.networks.facebook.image,
20682        caption: this.config.networks.facebook.caption,
20683        description: this.config.networks.facebook.description
20684      });
20685    } else {
20686      return this.popup('https://www.facebook.com/sharer/sharer.php', {
20687        u: this.config.networks.facebook.url
20688      });
20689    }
20690  };
20691
20692  Share.prototype.network_twitter = function() {
20693    return this.popup('https://twitter.com/intent/tweet', {
20694      text: this.config.networks.twitter.title,
20695      url: this.config.networks.twitter.url
20696    });
20697  };
20698
20699  Share.prototype.network_pinterest = function() {
20700    return this.popup('https://www.pinterest.com/pin/create/button', {
20701      url: this.config.networks.pinterest.url,
20702      media: this.config.networks.pinterest.image,
20703      description: this.config.networks.pinterest.description
20704    });
20705  };
20706
20707  Share.prototype.network_linkedin = function() {
20708    return this.popup('https://www.linkedin.com/shareArticle', {
20709      url: this.config.networks.linkedin.url,
20710      title: this.config.networks.linkedin.title,
20711      summary: this.config.networks.linkedin.description
20712    });
20713  }
20714
20715  Share.prototype.network_xing = function() {
20716    return this.popup('https://www.xing.com/spi/shares/new', {
20717      url: this.config.networks.xing.url,
20718      image: this.config.networks.xing.image,
20719      title: this.config.networks.xing.title,
20720      summary: this.config.networks.xing.description
20721    });
20722  }
20723
20724  Share.prototype.network_email = function() {
20725    return this.popup('mailto:', {
20726      subject: this.config.networks.email.title,
20727      body: this.config.networks.email.url + '%0A%0A' + this.config.networks.email.description,
20728    });
20729  };
20730
20731  Share.prototype.inject_icons = function() {
20732  //  return this.inject_stylesheet("https://www.sharebutton.co/fonts/v2/entypo.min.css");
20733  };
20734
20735  Share.prototype.inject_fonts = function() {
20736   // return this.inject_stylesheet("http://fonts.googleapis.com/css?family=Lato:900&text=" + this.config.ui.button_text);
20737  };
20738
20739  Share.prototype.inject_stylesheet = function(url) {
20740    var link;
20741    if (!this.el.head.querySelector("link[href=\"" + url + "\"]")) {
20742      link = document.createElement("link");
20743      link.setAttribute("rel", "stylesheet");
20744      link.setAttribute("href", url);
20745      return this.el.head.appendChild(link);
20746    }
20747  };
20748
20749  Share.prototype.inject_css = function(instance) {
20750    var css, meta, selector, style;
20751    selector = "." + (instance.getAttribute('class').split(" ").join("."));
20752    if (!this.el.head.querySelector("meta[name='sharer" + selector + "']")) {
20753      this.config.selector = selector;
20754      css = getStyles(this.config);
20755      style = document.createElement("style");
20756      style.type = "text/css";
20757      if (style.styleSheet) {
20758        style.styleSheet.cssText = css;
20759      } else {
20760        style.appendChild(document.createTextNode(css));
20761      }
20762      this.el.head.appendChild(style);
20763      delete this.config.selector;
20764      meta = document.createElement("meta");
20765      meta.setAttribute("name", "sharer" + selector);
20766      return this.el.head.appendChild(meta);
20767    }
20768  };
20769
20770  Share.prototype.inject_html = function(instance) {
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-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>";
20772    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>";
20773  };
20774
20775  Share.prototype.inject_facebook_sdk = function() {
20776    var fb_root, script;
20777    if (!window.FB && this.config.networks.facebook.app_id && !this.el.body.querySelector('#fb-root')) {
20778      script = document.createElement("script");
20779      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')";
20780      fb_root = document.createElement("div");
20781      fb_root.id = "fb-root";
20782      this.el.body.appendChild(fb_root);
20783      return this.el.body.appendChild(script);
20784    }
20785  };
20786
20787  Share.prototype.hook = function(type, network, instance) {
20788    var fn, opts;
20789    fn = this.config.networks[network][type];
20790    if (typeof fn === "function") {
20791      opts = fn.call(this.config.networks[network], instance);
20792      if (opts !== void 0) {
20793        opts = this.normalize_filter_config_updates(opts);
20794        this.extend(this.config.networks[network], opts, true);
20795        this.normalize_network_configuration();
20796      }
20797    }
20798  };
20799
20800  Share.prototype.default_title = function() {
20801    var content;
20802    if (content = document.querySelector('meta[property="og:title"]') || document.querySelector('meta[name="twitter:title"]')) {
20803      return encodeURIComponent(content.getAttribute('content'));
20804    } else if (content = document.querySelector('title')) {
20805      return encodeURIComponent(content.innerText);
20806    }
20807  };
20808
20809  Share.prototype.default_image = function() {
20810    var content;
20811    if (content = document.querySelector('meta[property="og:image"]') || document.querySelector('meta[name="twitter:image"]')) {
20812      return content.getAttribute('content');
20813    }
20814  };
20815
20816  Share.prototype.default_description = function() {
20817    var content;
20818    if (content = document.querySelector('meta[property="og:description"]') || document.querySelector('meta[name="twitter:description"]') || document.querySelector('meta[name="description"]')) {
20819      return encodeURIComponent(content.getAttribute('content'));
20820    } else {
20821      return '';
20822    }
20823  };
20824
20825  Share.prototype.set_global_configuration = function() {
20826    var display, network, option, options, _ref, _results;
20827    _ref = this.config.networks;
20828    _results = [];
20829    for (network in _ref) {
20830      options = _ref[network];
20831      for (option in options) {
20832        if (this.config.networks[network][option] == null) {
20833          this.config.networks[network][option] = this.config[option];
20834        }
20835      }
20836      if (this.config.networks[network].enabled) {
20837        display = 'block';
20838        this.config.enabled_networks += 1;
20839      } else {
20840        display = 'none';
20841      }
20842      _results.push(this.config.networks[network].display = display);
20843    }
20844    return _results;
20845  };
20846
20847  Share.prototype.normalize_network_configuration = function() {
20848    if (!this.config.networks.facebook.app_id) {
20849      this.config.networks.facebook.load_sdk = false;
20850    }
20851    if (!this.is_encoded(this.config.networks.twitter.description)) {
20852      this.config.networks.twitter.description = encodeURIComponent(this.config.networks.twitter.description);
20853    }
20854    if (typeof this.config.networks.facebook.app_id === 'number') {
20855      return this.config.networks.facebook.app_id = this.config.networks.facebook.app_id.toString();
20856    }
20857  };
20858
20859  Share.prototype.normalize_filter_config_updates = function(opts) {
20860    if (this.config.networks.facebook.app_id !== opts.app_id) {
20861      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.");
20862      delete opts.app_id;
20863    }
20864    if (this.config.networks.facebook.load_sdk !== opts.load_sdk) {
20865      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.");
20866      delete opts.app_id;
20867    }
20868    return opts;
20869  };
20870
20871  return Share;
20872
20873})(ShareUtils);
20874 return Share;
20875});
20876
20877// Generated by CoffeeScript 1.9.2
20878
20879// @license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
20880
20881(function() {
20882  var $, win;
20883
20884  $ = this.jQuery || window.jQuery;
20885
20886  win = $(window);
20887
20888  $.fn.stick_in_parent = function(opts) {
20889    var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
20890    if (opts == null) {
20891      opts = {};
20892    }
20893    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;
20894    if (offset_top == null) {
20895      offset_top = 0;
20896    }
20897    if (parent_selector == null) {
20898      parent_selector = void 0;
20899    }
20900    if (inner_scrolling == null) {
20901      inner_scrolling = true;
20902    }
20903    if (sticky_class == null) {
20904      sticky_class = "is_stuck";
20905    }
20906    doc = $(document);
20907    if (enable_bottoming == null) {
20908      enable_bottoming = true;
20909    }
20910    outer_width = function(el) {
20911      var _el, computed, w;
20912      if (window.getComputedStyle) {
20913        _el = el[0];
20914        computed = window.getComputedStyle(el[0]);
20915        w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
20916        if (computed.getPropertyValue("box-sizing") !== "border-box") {
20917          w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
20918        }
20919        return w;
20920      } else {
20921        return el.outerWidth(true);
20922      }
20923    };
20924    fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
20925      var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
20926      if (elm.data("sticky_kit")) {
20927        return;
20928      }
20929      elm.data("sticky_kit", true);
20930      last_scroll_height = doc.height();
20931      parent = elm.parent();
20932      if (parent_selector != null) {
20933        parent = parent.closest(parent_selector);
20934      }
20935      if (!parent.length) {
20936        throw "failed to find stick parent";
20937      }
20938      fixed = false;
20939      bottomed = false;
20940      spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
20941      if (spacer) {
20942        spacer.css('position', elm.css('position'));
20943      }
20944      recalc = function() {
20945        var border_top, padding_top, restore;
20946        if (detached) {
20947          return;
20948        }
20949        last_scroll_height = doc.height();
20950        border_top = parseInt(parent.css("border-top-width"), 10);
20951        padding_top = parseInt(parent.css("padding-top"), 10);
20952        padding_bottom = parseInt(parent.css("padding-bottom"), 10);
20953        parent_top = parent.offset().top + border_top + padding_top;
20954        parent_height = parent.height();
20955        if (fixed) {
20956          fixed = false;
vendor: 6,068 bytes, lines 20957-21151
20957          bottomed = false;
20958          if (manual_spacer == null) {
20959            elm.insertAfter(spacer);
20960            spacer.detach();
20961          }
20962          elm.css({
20963            position: "",
20964            top: "",
20965            width: "",
20966            bottom: ""
20967          }).removeClass(sticky_class);
20968          restore = true;
20969        }
20970        top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
20971        height = elm.outerHeight(true);
20972        el_float = elm.css("float");
20973        if (spacer) {
20974          spacer.css({
20975            width: outer_width(elm),
20976            height: height,
20977            display: elm.css("display"),
20978            "vertical-align": elm.css("vertical-align"),
20979            "float": el_float
20980          });
20981        }
20982        if (restore) {
20983          return tick();
20984        }
20985      };
20986      recalc();
20987      if (height === parent_height) {
20988        return;
20989      }
20990      last_pos = void 0;
20991      offset = offset_top;
20992      recalc_counter = recalc_every;
20993      tick = function() {
20994        var css, delta, recalced, scroll, will_bottom, win_height;
20995        if (detached) {
20996          return;
20997        }
20998        recalced = false;
20999        if (recalc_counter != null) {
21000          recalc_counter -= 1;
21001          if (recalc_counter <= 0) {
21002            recalc_counter = recalc_every;
21003            recalc();
21004            recalced = true;
21005          }
21006        }
21007        if (!recalced && doc.height() !== last_scroll_height) {
21008          recalc();
21009          recalced = true;
21010        }
21011        scroll = win.scrollTop();
21012        if (last_pos != null) {
21013          delta = scroll - last_pos;
21014        }
21015        last_pos = scroll;
21016        if (fixed) {
21017          if (enable_bottoming) {
21018            will_bottom = scroll + height + offset > parent_height + parent_top;
21019            if (bottomed && !will_bottom) {
21020              bottomed = false;
21021              elm.css({
21022                position: "fixed",
21023                bottom: "",
21024                top: offset
21025              }).trigger("sticky_kit:unbottom");
21026            }
21027          }
21028          if (scroll < top) {
21029            fixed = false;
21030            offset = offset_top;
21031            if (manual_spacer == null) {
21032              if (el_float === "left" || el_float === "right") {
21033                elm.insertAfter(spacer);
21034              }
21035              spacer.detach();
21036            }
21037            css = {
21038              position: "",
21039              width: "",
21040              top: ""
21041            };
21042            elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
21043          }
21044          if (inner_scrolling) {
21045            win_height = win.height();
21046            if (height + offset_top > win_height) {
21047              if (!bottomed) {
21048                offset -= delta;
21049                offset = Math.max(win_height - height, offset);
21050                offset = Math.min(offset_top, offset);
21051                if (fixed) {
21052                  elm.css({
21053                    top: offset + "px"
21054                  });
21055                }
21056              }
21057            }
21058          }
21059        } else {
21060          if (scroll > top) {
21061            fixed = true;
21062            css = {
21063              position: "fixed",
21064              top: offset
21065            };
21066            css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
21067            elm.css(css).addClass(sticky_class);
21068            if (manual_spacer == null) {
21069              elm.after(spacer);
21070              if (el_float === "left" || el_float === "right") {
21071                spacer.append(elm);
21072              }
21073            }
21074            elm.trigger("sticky_kit:stick");
21075          }
21076        }
21077        if (fixed && enable_bottoming) {
21078          if (will_bottom == null) {
21079            will_bottom = scroll + height + offset > parent_height + parent_top;
21080          }
21081          if (!bottomed && will_bottom) {
21082            bottomed = true;
21083            if (parent.css("position") === "static") {
21084              parent.css({
21085                position: "relative"
21086              });
21087            }
21088            return elm.css({
21089              position: "absolute",
21090              bottom: padding_bottom,
21091              top: "auto"
21092            }).trigger("sticky_kit:bottom");
21093          }
21094        }
21095      };
21096      recalc_and_tick = function() {
21097        recalc();
21098        return tick();
21099      };
21100      detach = function() {
21101        detached = true;
21102        win.off("touchmove", tick);
21103        win.off("scroll", tick);
21104        win.off("resize", recalc_and_tick);
21105        $(document.body).off("sticky_kit:recalc", recalc_and_tick);
21106        elm.off("sticky_kit:detach", detach);
21107        elm.removeData("sticky_kit");
21108        elm.css({
21109          position: "",
21110          bottom: "",
21111          top: "",
21112          width: ""
21113        });
21114        parent.position("position", "");
21115        if (fixed) {
21116          if (manual_spacer == null) {
21117            if (el_float === "left" || el_float === "right") {
21118              elm.insertAfter(spacer);
21119            }
21120            spacer.remove();
21121          }
21122          return elm.removeClass(sticky_class);
21123        }
21124      };
21125      win.on("touchmove", tick);
21126      win.on("scroll", tick);
21127      win.on("resize", recalc_and_tick);
21128      $(document.body).on("sticky_kit:recalc", recalc_and_tick);
21129      elm.on("sticky_kit:detach", detach);
21130      return setTimeout(tick, 0);
21131    };
21132    for (i = 0, len = this.length; i < len; i++) {
21133      elm = this[i];
21134      fn($(elm));
21135    }
21136    return this;
21137  };
21138
21139}).call(this);
21140/* ==========================================================================
21141 * bootstrap-tab-history.js
21142 * Author: Michael Narayan <[email protected]>
21143 * Repository: https://github.com/mnarayan01/bootstrap-tab-history/
21144 * ==========================================================================
21145 * Licensed under the Apache License, Version 2.0 (the "License"); you may
21146 * not use this file except in compliance with the License. You may obtain a
21147 * copy of the License at
21148 *
21149 * http://www.apache.org/licenses/LICENSE-2.0
21150 *
21151 * Unless required by applicable law or agreed to in writing, softw
21151are
21152 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21153 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
21154 * License for the specific language governing permissions and limitations
21155 * under the License.
21156 * ========================================================================== */
21157
21158/* ========================================================================== */
21159/* JSHint directives                                                          */
21160/*                                                                            */
21161/* global BootstrapTabHistory: true                                           */
21162/*                                                                            */
21163/* global document                                                            */
21164/* global jQuery                                                              */
21165/* global history                                                             */
21166/* global window                                                              */
21167/* ========================================================================== */
21168
21169/**
21170 * Integrate [HTML5 history state tracking](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
21171 * with [`bootstrap/tab.js`](http://getbootstrap.com/javascript/#tabs). To enable tracking on a tab element, simply set
21172 * the `data-tab-history` attribute to true (or a string denoting a tab grouping).
21173 *
21174 * See the README for additional information.
21175 *
21176 * Functionality based upon bootstrap/tab.js v3.1.0; reference it when making any changes.
21177 */
21178
21179BootstrapTabHistory = {
21180  options: {
21181    /**
21182     * When the anchor portion of the URI is used to activate a tab, scroll down to the given offset, rather than the
21183     * element with the given `id` attribute. Set to null to disable. Only relevant if showTabsBasedOnAnchor is true.
21184     *
21185     * May be overriden on a per-element basis by the attribute `data-tab-history-anchor-y-offset`.
21186     *
21187     * @public
21188     * @type {?number}
21189     */
21190    defaultAnchorYOffset: 0,
21191    /**
21192     * Either 'push' or 'replace', for whether to use `history.pushState` or `history.replaceState`, resp.
21193     *
21194     * May be overriden on a per-element basis by the attribute `data-tab-history-changer`.
21195     *
21196     * @public
21197     * @type {string}
21198     */
21199    defaultChanger: 'replace',
21200    /**
21201     * If true, update the URL in onShownTab in the calls to `history.pushState` and `history.replaceState`. Otherwise,
21202     * `null` is passed as the third parameter to these calls.
21203     *
21204     * May be overriden on a per-element basis by the attribute `data-tab-history-update-url`.
21205     *
21206     * @public
21207     * @type {boolean}
21208     */
21209    defaultUpdateURL: false,
21210    /**
21211     * Should the anchor portion of the loaded URI be used to activate a single tab if no history was present on page
21212     * load.
21213     *
21214     * @public
21215     * @type {boolean}
21216     */
21217    showTabsBasedOnAnchor: true
21218  }
21219};
21220
21221(function () {
21222  'use strict';
21223
21224  jQuery(function () {
21225    if(history && history.pushState && history.replaceState) {
21226      var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
21227
21228      if(bootstrapTabHistory) {
21229        showTabsBasedOnState(bootstrapTabHistory);
21230      } else {
21231        showTabsBasedOnAnchor();
21232      }
21233
21234      backfillHistoryState();
21235
21236      jQuery(document).on('shown.bs.tab show.bs.collapse', onShownTab);
21237      jQuery(window).on('popstate', onPopState);
21238    } else {
21239      showTabsBasedOnAnchor();
21240    }
21241  });
21242
21243  /**
21244   * Used to prevent onShownTab from registering shown events that we triggered via showTabsBasedOnState.
21245   *
21246   * @type {boolean}
21247   */
21248  var showingTabsBasedOnState = false;
21249
21250  /**
21251   * Used to update `history.state` to reflect the default active tabs on initial page load. This supports proper
21252   * `history.back` handling when `data-tab-history-update-url` is true.
21253   */
21254  function backfillHistoryState() {
21255    var newState = null;
21256
21257    jQuery('li.active > [data-tab-history], .panel-title.active [data-tab-history]').each(function () {//edited by Uncode
21258      var $activeTabElement = jQuery(this);
21259      var selector = getTabSelector($activeTabElement);
21260
21261      if(selector) {
21262        var tabGroup = getTabGroup($activeTabElement);
21263
21264        if(tabGroup) {
21265          newState = createNewHistoryState(newState || history.state, tabGroup, selector);
21266        }
21267      }
21268    });
21269
21270    if(newState) {
21271      history.replaceState(newState, '', null);
21272    }
21273  }
21274
21275  /**
21276   * Clone the existing state, ensure its bootstrapTabHistory attribute is an Object, and add the provided tabGroup to
21277   * said bootstrapTabHistory attribute.
21278   *
21279   * @param {?object} existingState
21280   * @param {!string} tabGroup
21281   * @param {!string} selector
21282   * @returns {!object}
21283   */
21284  function createNewHistoryState(existingState, tabGroup, selector) {
21285    // Clone history.state and ensure it has a bootstrapTabHistory entry.
21286    var newState = jQuery.extend(true, {}, existingState, {
21287      bootstrapTabHistory: {}
21288    });
21289
21290    newState.bootstrapTabHistory[tabGroup] = selector;
21291
21292    return newState;
21293  }
21294
21295  /**
21296   * @param {jQuery} $tab
21297   * @returns {?string}
21298   */
21299  function getTabGroup($tab) {
21300    return parseTruthyAttributeValue($tab.data('tab-history'));
21301  }
21302
21303  /**
21304   * @param {jQuery} $tab
21305   * @returns {?string}
21306   */
21307  function getTabSelector($tab) {
21308    return $tab.data('target') || $tab.attr('href');
21309  }
21310
21311  /**
21312   * Receives the `shown.bs.tab` event. Updates `history.state` as appropriate.
21313   *
21314   * @param {jQuery.Event} shownEvt
21315   */
21316  function onShownTab(shownEvt) {
21317    if(!showingTabsBasedOnState) {
21318      var $activatedTab = jQuery(shownEvt.target);
21319      if ( $activatedTab.hasClass('panel-collapse') )
21320        $activatedTab = $activatedTab.closest('.panel').find('a');
21321      var selector = getTabSelector($activatedTab);
21322
21323      if(selector) {
21324        var tabGroup = getTabGroup($activatedTab);
21325
21326        if(tabGroup) {
21327          var historyChanger = $activatedTab.data('tab-history-changer') || BootstrapTabHistory.options.defaultChanger;
21328          var newState = createNewHistoryState(history.state, tabGroup, selector);
21329          var updateURL = (function ($activatedTab) {
21330            if(selector[0] === '#') {
21331              var elementUpdateURLOption = parseTruthyAttributeValue($activatedTab.data('tab-history-update-url'));
21332
21333              if(elementUpdateURLOption === undefined) {
21334                return BootstrapTabHistory.options.defaultUpdateURL;
21335              } else {
21336                return elementUpdateURLOption;
21337              }
21338            } else {
21339              return false;
21340            }
21341          })($activatedTab);
21342
21343          switch(historyChanger) {
21344            case 'push':
21345              history.pushState(newState, '', updateURL ? selector : null);
21346              break;
21347            case 'replace':
21348              history.replaceState(newState, '', updateURL ? selector : null);
21349              break;
21350            default:
21351              throw new Error('Unknown tab-history-changer: ' + historyChanger);
21352          }
21353        }
21354      }
21355    }
21356  }
21357
21358  /**
21359   * Receives the `popstate` event. Shows tabs based on the value of `history.state` as appropriate.
21360   */
21361  function onPopState() {
21362    var bootstrapTabHistory = history.state && history.state.bootstrapTabHistory;
21363
21364    if(bootstrapTabHistory) {
21365      showTabsBasedOnState(bootstrapTabHistory);
21366    }
21367  }
21368
21369  /**
21370   * Returns the given value, _unless_ that value is an empty string, in which case `true` is returned.
21371   *
21372   * Rationale: HAML data attributes which are set to `true` are rendered as a blank string.
21373   *
21374   * @param {*} value
21375   * @returns {*}
21376   */
21377  function parseTruthyAttributeValue(value) {
21378    if(value) {
21379      return value;
21380    } else if(value === '') {
21381      return true;
21382    } else {
21383      return value;
21384    }
21385  }
21386
21387  /**
21388   * Show tabs based upon the anchor component of `window.location`.
21389   */
21390  function showTabsBasedOnAnchor() {
21391    if(BootstrapTabHistory.options.showTabsBasedOnAnchor) {
21392      var anchor = window.location && window.location.hash;
21393
21394      if(anchor) {
21395        var $tabElement = showTabForSelector(anchor);
21396
21397        if($tabElement && window.addEventListener && window.removeEventListener) {
21398          var anchorYOffset = (function ($tabElement) {
21399            var elementSetting = $tabElement.data('tab-history-anchor-y-offset');
21400
21401            if(elementSetting === undefined) {
21402              return BootstrapTabHistory.options.defaultAnchorYOffset;
21403            } else {
21404              return elementSetting;
21405            }
21406          })($tabElement);
21407
21408          // HACK: This prevents scrolling to the tab on page load. This relies on the fact that we should never get
21409          //   here on `history.forward`, `history.back`, or `location.reload`, since in all those situations the
21410          //   `history.state` object should have been used (unless the browser did not support the modern History API).
21411          if(anchorYOffset || anchorYOffset === 0) {
21412            var scrollListener = function resetAnchorScroll () {
21413              window.removeEventListener('scroll', scrollListener);
21414              window.scrollTo(0, anchorYOffset);
21415            };
21416
21417            window.addEventListener('scroll', scrollListener);
21418          }
21419        }
21420      }
21421    }
21422  }
21423
21424  /**
21425   * Show a tab which corresponds to the provided selector.
21426   *
21427   * @param {string} selector - A CSS selector.
21428   * @returns {?jQuery} - The tab which was found to show (even if said tab was already active).
21429   */
21430  function showTabForSelector(selector) {
21431    var $tabElement = (function (selector) {
21432      var $ret = null;
21433
21434      jQuery('[data-toggle="tab"], [data-toggle="pill"], [data-toggle="collapse"]').each(function () {
21435        var $potentialTab = jQuery(this);
21436
21437        if(($potentialTab.attr('href') === selector || $potentialTab.data('target') === selector ) && getTabGroup($potentialTab)) {
21438          $ret = $potentialTab;
21439          return false;
vendor: 43,417 bytes, lines 21440-22654
21440        } else {
21441         return null;
21442        }
21443      });
21444
21445      return $ret;
21446    })(selector);
21447
21448    if($tabElement) {
21449      $tabElement.trigger('click');
21450      //$tabElement.tab('show');
21451    }
21452
21453    return $tabElement;
21454  }
21455
21456  /**
21457   * Iterate through the provided set of tab tab groups, showing the tabs based on the stored selectors.
21458   *
21459   * @param {object} bootstrapTabHistory - Each of the values is passed to showTabForSelector; the keys are actually irrelevant.
21460   */
21461  function showTabsBasedOnState(bootstrapTabHistory) {
21462    showingTabsBasedOnState = true;
21463
21464    try {
21465      for(var k in bootstrapTabHistory) {
21466        if(bootstrapTabHistory.hasOwnProperty(k)) {
21467          showTabForSelector(bootstrapTabHistory[k]);
21468        }
21469      }
21470    } finally {
21471      showingTabsBasedOnState = false;
21472    }
21473  }
21474})();
21475
21476/*!
21477 * justifiedGallery - v3.8.1
21478 * http://miromannino.github.io/Justified-Gallery/
21479 * Copyright (c) 2020 Miro Mannino
21480 * Licensed under the MIT license.
21481 */
21482(function (factory) {
21483  if (typeof define === 'function' && define.amd) {
21484    // AMD. Register as an anonymous module.
21485    define(['jquery'], factory);
21486  } else if (typeof module === 'object' && module.exports) {
21487    // Node/CommonJS
21488    module.exports = function (root, jQuery) {
21489      if (jQuery === undefined) {
21490        // require('jQuery') returns a factory that requires window to
21491        // build a jQuery instance, we normalize how we use modules
21492        // that require this pattern but the window provided is a noop
21493        // if it's defined (how jquery works)
21494        if (typeof window !== 'undefined') {
21495          jQuery = require('jquery');
21496        }
21497        else {
21498          jQuery = require('jquery')(root);
21499        }
21500      }
21501      factory(jQuery);
21502      return jQuery;
21503    };
21504  } else {
21505    // Browser globals
21506    factory(jQuery);
21507  }
21508}(function ($) {
21509
21510  /**
21511   * Justified Gallery controller constructor
21512   *
21513   * @param $gallery the gallery to build
21514   * @param settings the settings (the defaults are in JustifiedGallery.defaults)
21515   * @constructor
21516   */
21517  var JustifiedGallery = function ($gallery, settings) {
21518
21519    this.settings = settings;
21520    this.checkSettings();
21521
21522    this.imgAnalyzerTimeout = null;
21523    this.entries = null;
21524    this.buildingRow = {
21525      entriesBuff: [],
21526      width: 0,
21527      height: 0,
21528      aspectRatio: 0
21529    };
21530    this.lastFetchedEntry = null;
21531    this.lastAnalyzedIndex = -1;
21532    this.yield = {
21533      every: 2, // do a flush every n flushes (must be greater than 1)
21534      flushed: 0 // flushed rows without a yield
21535    };
21536    this.border = settings.border >= 0 ? settings.border : settings.margins;
21537    this.maxRowHeight = this.retrieveMaxRowHeight();
21538    this.suffixRanges = this.retrieveSuffixRanges();
21539    this.offY = this.border;
21540    this.rows = 0;
21541    this.spinner = {
21542      phase: 0,
21543      timeSlot: 150,
21544      $el: $('<div class="jg-spinner"><span></span><span></span><span></span></div>'),
21545      intervalId: null
21546    };
21547    this.scrollBarOn = false;
21548    this.checkWidthIntervalId = null;
21549    this.galleryWidth = $gallery.width();
21550    this.$gallery = $gallery;
21551
21552  };
21553
21554  /** @returns {String} the best suffix given the width and the height */
21555  JustifiedGallery.prototype.getSuffix = function (width, height) {
21556    var longestSide, i;
21557    longestSide = (width > height) ? width : height;
21558    for (i = 0; i < this.suffixRanges.length; i++) {
21559      if (longestSide <= this.suffixRanges[i]) {
21560        return this.settings.sizeRangeSuffixes[this.suffixRanges[i]];
21561      }
21562    }
21563    return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]];
21564  };
21565
21566  /**
21567   * Remove the suffix from the string
21568   *
21569   * @returns {string} a new string without the suffix
21570   */
21571  JustifiedGallery.prototype.removeSuffix = function (str, suffix) {
21572    return str.substring(0, str.length - suffix.length);
21573  };
21574
21575  /**
21576   * @returns {boolean} a boolean to say if the suffix is contained in the str or not
21577   */
21578  JustifiedGallery.prototype.endsWith = function (str, suffix) {
21579    return str.indexOf(suffix, str.length - suffix.length) !== -1;
21580  };
21581
21582  /**
21583   * Get the used suffix of a particular url
21584   *
21585   * @param str
21586   * @returns {String} return the used suffix
21587   */
21588  JustifiedGallery.prototype.getUsedSuffix = function (str) {
21589    for (var si in this.settings.sizeRangeSuffixes) {
21590      if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) {
21591        if (this.settings.sizeRangeSuffixes[si].length === 0) continue;
21592        if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si];
21593      }
21594    }
21595    return '';
21596  };
21597
21598  /**
21599   * Given an image src, with the width and the height, returns the new image src with the
21600   * best suffix to show the best quality thumbnail.
21601   *
21602   * @returns {String} the suffix to use
21603   */
21604  JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight, image) {
21605    var newImageSrc;
21606
21607    if (this.settings.thumbnailPath) {
21608      newImageSrc = this.settings.thumbnailPath(imageSrc, imgWidth, imgHeight, image);
21609    } else {
21610      var matchRes = imageSrc.match(this.settings.extension);
21611      var ext = (matchRes !== null) ? matchRes[0] : '';
21612      newImageSrc = imageSrc.replace(this.settings.extension, '');
21613      newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc));
21614      newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext;
21615    }
21616
21617    return newImageSrc;
21618  };
21619
21620  /**
21621   * Shows the images that is in the given entry
21622   *
21623   * @param $entry the entry
21624   * @param callback the callback that is called when the show animation is finished
21625   */
21626  JustifiedGallery.prototype.showImg = function ($entry, callback) {
21627    if (this.settings.cssAnimation) {
21628      $entry.addClass('jg-entry-visible');
21629      if (callback) callback();
21630    } else {
21631      $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
21632      $entry.find(this.settings.imgSelector).stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback);
21633    }
21634  };
21635
21636  /**
21637   * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the
21638   * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src.
21639   *
21640   * @param $image the image to analyze
21641   * @returns {String} the extracted src
21642   */
21643  JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) {
21644    var imageSrc = $image.data('safe-src');
21645    var imageSrcLoc = 'data-safe-src';
21646    // Begin Uncode edit
21647    if (typeof imageSrc === 'undefined') {
21648    	var imageCurrentSrc = $image[0].currentSrc;
21649    	if (imageCurrentSrc) {
21650    		imageSrc = imageCurrentSrc;
21651    	} else {
21652    		imageSrc = $image.attr('src');
21653    	}
21654		imageSrcLoc = 'src';
21655    }
21656    // End Uncode edit
21657    $image.data('jg.originalSrc', imageSrc); // this is saved for the destroy method
21658    $image.data('jg.src', imageSrc); // this will change overtime
21659    $image.data('jg.originalSrcLoc', imageSrcLoc); // this is saved for the destroy method
21660    return imageSrc;
21661  };
21662
21663  /** @returns {jQuery} the image in the given entry */
21664  JustifiedGallery.prototype.imgFromEntry = function ($entry) {
21665    var $img = $entry.find(this.settings.imgSelector);
21666    if ($img.length === 0) $img = $entry.find('.t-entry-visual-cont img');//hacked by Uncode
21667    return $img.length === 0 ? null : $img;
21668  };
21669
21670  /** @returns {jQuery} the caption in the given entry */
21671  JustifiedGallery.prototype.captionFromEntry = function ($entry) {
21672    var $caption = $entry.find('> .jg-caption');
21673    return $caption.length === 0 ? null : $caption;
21674  };
21675
21676  /**
21677   * Display the entry
21678   *
21679   * @param {jQuery} $entry the entry to display
21680   * @param {int} x the x position where the entry must be positioned
21681   * @param y the y position where the entry must be positioned
21682   * @param imgWidth the image width
21683   * @param imgHeight the image height
21684   * @param rowHeight the row height of the row that owns the entry
21685   */
21686  JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) {
21687    $entry.width(imgWidth);
21688    $entry.height(Math.floor(rowHeight));//hacked by Uncode
21689    $entry.css('top', Math.floor(y));//hacked by Uncode
21690    $entry.css('left', x);
21691
21692    var $image = this.imgFromEntry($entry);
21693    if ($image !== null) {
21694      $image.css('width', imgWidth);
21695      $image.css('height', imgHeight);
21696      $image.css('margin-left', - imgWidth / 2);
21697      $image.css('margin-top', - imgHeight / 2);
21698
21699      // Image reloading for an high quality of thumbnails
21700      var imageSrc = $image.data('jg.src');
21701      if (imageSrc) {
21702        imageSrc = this.newSrc(imageSrc, imgWidth, imgHeight, $image[0]);
21703
21704        $image.one('error', function () {
21705           this.resetImgSrc($image); //revert to the original thumbnail
21706        });
21707
21708        var loadNewImage = function () {
21709          // if (imageSrc !== newImageSrc) {
21710            $image.attr('src', imageSrc);
21711          // }
21712        };
21713
21714        if ($entry.data('jg.loaded') === 'skipped' && imageSrc) {
21715          this.onImageEvent(imageSrc, (function() {
21716            this.showImg($entry, loadNewImage); //load the new image after the fadeIn
21717            $entry.data('jg.loaded', true);
21718          }).bind(this));
21719        } else {
21720          this.showImg($entry, loadNewImage); //load the new image after the fadeIn
21721        }
21722
21723      }
21724
21725    } else {
21726      this.showImg($entry);
21727    }
21728
21729    this.displayEntryCaption($entry);
21730  };
21731
21732  /**
21733   * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt'
21734   * or the 'title' attributes.
21735   *
21736   * @param {jQuery} $entry the entry to process
21737   */
21738  JustifiedGallery.prototype.displayEntryCaption = function ($entry) {
21739    var $image = this.imgFromEntry($entry);
21740    if ($image !== null && this.settings.captions) {
21741      var $imgCaption = this.captionFromEntry($entry);
21742
21743      // Create it if it doesn't exists
21744      if ($imgCaption === null) {
21745        var caption = $image.attr('alt');
21746        if (!this.isValidCaption(caption)) caption = $entry.attr('title');
21747        if (this.isValidCaption(caption)) { // Create only we found something
21748          $imgCaption = $('<div class="jg-caption">' + caption + '</div>');
21749          $entry.append($imgCaption);
21750          $entry.data('jg.createdCaption', true);
21751        }
21752      }
21753
21754      // Create events (we check again the $imgCaption because it can be still inexistent)
21755      if ($imgCaption !== null) {
21756        if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity);
21757        this.addCaptionEventsHandlers($entry);
21758      }
21759    } else {
21760      this.removeCaptionEventsHandlers($entry);
21761    }
21762  };
21763
21764  /**
21765   * Validates the caption
21766   *
21767   * @param caption The caption that should be validated
21768   * @return {boolean} Validation result
21769   */
21770  JustifiedGallery.prototype.isValidCaption = function (caption) {
21771    return (typeof caption !== 'undefined' && caption.length > 0);
21772  };
21773
21774  /**
21775   * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry.
21776   * It shows the caption using jQuery (or using CSS if it is configured so)
21777   *
21778   * @param {Event} eventObject the event object
21779   */
21780  JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) {
21781    var $caption = this.captionFromEntry($(eventObject.currentTarget));
21782    if (this.settings.cssAnimation) {
21783      $caption.addClass('jg-caption-visible').removeClass('jg-caption-hidden');
21784    } else {
21785      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
21786        this.settings.captionSettings.visibleOpacity);
21787    }
21788  };
21789
21790  /**
21791   * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry.
21792   * It hides the caption using jQuery (or using CSS if it is configured so)
21793   *
21794   * @param {Event} eventObject the event object
21795   */
21796  JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) {
21797    var $caption = this.captionFromEntry($(eventObject.currentTarget));
21798    if (this.settings.cssAnimation) {
21799      $caption.removeClass('jg-caption-visible').removeClass('jg-caption-hidden');
21800    } else {
21801      $caption.stop().fadeTo(this.settings.captionSettings.animationDuration,
21802        this.settings.captionSettings.nonVisibleOpacity);
21803    }
21804  };
21805
21806  /**
21807   * Add the handlers of the entry for the caption
21808   *
21809   * @param $entry the entry to modify
21810   */
21811  JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) {
21812    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
21813    if (typeof captionMouseEvents === 'undefined') {
21814      captionMouseEvents = {
21815        mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this),
21816        mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this)
21817      };
21818      $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter);
21819      $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave);
21820      $entry.data('jg.captionMouseEvents', captionMouseEvents);
21821    }
21822  };
21823
21824  /**
21825   * Remove the handlers of the entry for the caption
21826   *
21827   * @param $entry the entry to modify
21828   */
21829  JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) {
21830    var captionMouseEvents = $entry.data('jg.captionMouseEvents');
21831    if (typeof captionMouseEvents !== 'undefined') {
21832      $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter);
21833      $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave);
21834      $entry.removeData('jg.captionMouseEvents');
21835    }
21836  };
21837
21838  /**
21839   * Clear the building row data to be used for a new row
21840   */
21841  JustifiedGallery.prototype.clearBuildingRow = function () {
21842    this.buildingRow.entriesBuff = [];
21843    this.buildingRow.aspectRatio = 0;
21844    this.buildingRow.width = 0;
21845  };
21846
21847  /**
21848   * Justify the building row, preparing it to
21849   *
21850   * @param isLastRow
21851   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
21852   * @returns a boolean to know if the row has been justified or not
21853   */
21854  JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow, hiddenRow) {
21855    var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true;
21856    var minHeight = 0;
21857    var availableWidth = this.galleryWidth - 2 * this.border - (
21858      (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
21859    var rowHeight = Math.floor( availableWidth / this.buildingRow.aspectRatio );//hacked by Uncode
21860    var defaultRowHeight = this.settings.rowHeight;
21861    var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold;
21862
21863    //Skip the last row if we can't justify it and the lastRow == 'hide'
21864    if (hiddenRow || (isLastRow && this.settings.lastRow === 'hide' && !justifiable)) {
21865      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21866        $entry = this.buildingRow.entriesBuff[i];
21867        if (this.settings.cssAnimation)
21868          $entry.removeClass('jg-entry-visible');
21869        else {
21870          $entry.stop().fadeTo(0, 0.1);
21871          $entry.find('> img, > a > img').fadeTo(0, 0);
21872        }
21873      }
21874      return -1;
21875    }
21876
21877    // With lastRow = nojustify, justify if is justificable (the images will not become too big)
21878    if (isLastRow && !justifiable && this.settings.lastRow !== 'justify' && this.settings.lastRow !== 'hide') {
21879      justify = false;
21880
21881      if (this.rows > 0) {
21882        defaultRowHeight = (this.offY - this.border - this.settings.margins * this.rows) / this.rows;
21883        justify = defaultRowHeight * this.buildingRow.aspectRatio / availableWidth > this.settings.justifyThreshold;
21884      }
21885    }
21886
21887    for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21888      $entry = this.buildingRow.entriesBuff[i];
21889      imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
21890
21891      if (justify) {
21892        newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio;
21893        newImgH = rowHeight;
21894      } else {
21895        newImgW = defaultRowHeight * imgAspectRatio;
21896        newImgH = defaultRowHeight;
21897      }
21898
21899      availableWidth -= Math.round(newImgW);
21900      $entry.data('jg.jwidth', Math.round(newImgW));
21901      $entry.data('jg.jheight', Math.ceil(newImgH));
21902      if (i === 0 || minHeight > newImgH) minHeight = newImgH;
21903    }
21904
21905    this.buildingRow.height = minHeight;
21906    return justify;
21907  };
21908
21909  /**
21910   * Flush a row: justify it, modify the gallery height accordingly to the row height
21911   *
21912   * @param isLastRow
21913   * @param hiddenRow undefined or false for normal behavior. hiddenRow = true to hide the row.
21914   */
21915  JustifiedGallery.prototype.flushRow = function (isLastRow, hiddenRow) {
21916    var settings = this.settings;
21917    var $entry, buildingRowRes, offX = this.border, i;
21918
21919    buildingRowRes = this.prepareBuildingRow(isLastRow, hiddenRow);
21920    if (hiddenRow || (isLastRow && settings.lastRow === 'hide' && buildingRowRes === -1)) {
21921      this.clearBuildingRow();
21922      return;
21923    }
21924
21925    if (this.maxRowHeight) {
21926      if (this.maxRowHeight < this.buildingRow.height) this.buildingRow.height = this.maxRowHeight;
21927    }
21928
21929    //Align last (unjustified) row
21930    if (isLastRow && (settings.lastRow === 'center' || settings.lastRow === 'right')) {
21931      var availableWidth = this.galleryWidth - 2 * this.border - (this.buildingRow.entriesBuff.length - 1) * settings.margins;
21932
21933      for (i = 0; i < this.buildingRow.entriesBuff.length; i++) {
21934        $entry = this.buildingRow.entriesBuff[i];
21935        availableWidth -= $entry.data('jg.jwidth');
21936      }
21937
21938      if (settings.lastRow === 'center')
21939        offX += Math.round(availableWidth / 2);
21940      else if (settings.lastRow === 'right')
21941        offX += availableWidth;
21942    }
21943
21944    var lastEntryIdx = this.buildingRow.entriesBuff.length - 1;
21945    for (i = 0; i <= lastEntryIdx; i++) {
21946      $entry = this.buildingRow.entriesBuff[this.settings.rtl ? lastEntryIdx - i : i];
21947      this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), this.buildingRow.height);
21948      offX += $entry.data('jg.jwidth') + settings.margins;
21949    }
21950
21951    //Gallery Height
21952    this.galleryHeightToSet = this.offY + this.buildingRow.height + this.border;
21953    this.setGalleryTempHeight(this.galleryHeightToSet + this.getSpinnerHeight());
21954
21955    if (!isLastRow || (this.buildingRow.height <= settings.rowHeight && buildingRowRes)) {
21956      //Ready for a new row
21957      this.offY += this.buildingRow.height + settings.margins;
21958      this.rows += 1;
21959      this.clearBuildingRow();
21960      this.settings.triggerEvent.call(this, 'jg.rowflush');
21961    }
21962  };
21963
21964
21965  // Scroll position not restoring: https://github.com/miromannino/Justified-Gallery/issues/221
21966  var galleryPrevStaticHeight = 0;
21967
21968  JustifiedGallery.prototype.rememberGalleryHeight = function () {
21969    galleryPrevStaticHeight = this.$gallery.height();
21970    this.$gallery.height(galleryPrevStaticHeight);
21971  };
21972
21973  // grow only
21974  JustifiedGallery.prototype.setGalleryTempHeight = function (height) {
21975    galleryPrevStaticHeight = Math.max(height, galleryPrevStaticHeight);
21976    this.$gallery.height(galleryPrevStaticHeight);
21977  };
21978
21979  JustifiedGallery.prototype.setGalleryFinalHeight = function (height) {
21980    galleryPrevStaticHeight = height;
21981    this.$gallery.height(height);
21982  };
21983
21984  /**
21985   * Checks the width of the gallery container, to know if a new justification is needed
21986   */
21987  JustifiedGallery.prototype.checkWidth = function () {
21988    this.checkWidthIntervalId = setInterval($.proxy(function () {
21989
21990      // if the gallery is not currently visible, abort.
21991      if (!this.$gallery.is(":visible")) return;
21992
21993      var galleryWidth = parseFloat(this.$gallery.width());
21994      if (Math.abs(galleryWidth - this.galleryWidth) > this.settings.refreshSensitivity) {
21995        this.galleryWidth = galleryWidth;
21996        this.rewind();
21997
21998        this.rememberGalleryHeight();
21999
22000        // Restart to analyze
22001        this.startImgAnalyzer(true);
22002      }
22003    }, this), this.settings.refreshTime);
22004  };
22005
22006  /**
22007   * @returns {boolean} a boolean saying if the spinner is active or not
22008   */
22009  JustifiedGallery.prototype.isSpinnerActive = function () {
22010    return this.spinner.intervalId !== null;
22011  };
22012
22013  /**
22014   * @returns {int} the spinner height
22015   */
22016  JustifiedGallery.prototype.getSpinnerHeight = function () {
22017    return this.spinner.$el.innerHeight();
22018  };
22019
22020  /**
22021   * Stops the spinner animation and modify the gallery height to exclude the spinner
22022   */
22023  JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () {
22024    clearInterval(this.spinner.intervalId);
22025    this.spinner.intervalId = null;
22026    this.setGalleryTempHeight(this.$gallery.height() - this.getSpinnerHeight());
22027    this.spinner.$el.detach();
22028  };
22029
22030  /**
22031   * Starts the spinner animation
22032   */
22033  JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () {
22034    var spinnerContext = this.spinner;
22035    var $spinnerPoints = spinnerContext.$el.find('span');
22036    clearInterval(spinnerContext.intervalId);
22037    this.$gallery.append(spinnerContext.$el);
22038    this.setGalleryTempHeight(this.offY + this.buildingRow.height + this.getSpinnerHeight());
22039    spinnerContext.intervalId = setInterval(function () {
22040      if (spinnerContext.phase < $spinnerPoints.length) {
22041        $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1);
22042      } else {
22043        $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0);
22044      }
22045      spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2);
22046    }, spinnerContext.timeSlot);
22047  };
22048
22049  /**
22050   * Rewind the image analysis to start from the first entry.
22051   */
22052  JustifiedGallery.prototype.rewind = function () {
22053    this.lastFetchedEntry = null;
22054    this.lastAnalyzedIndex = -1;
22055    this.offY = this.border;
22056    this.rows = 0;
22057    this.clearBuildingRow();
22058  };
22059
22060  /**
22061   * @returns {String} `settings.selector` rejecting spinner element
22062   */
22063  JustifiedGallery.prototype.getSelectorWithoutSpinner = function () {
22064    return this.settings.selector + ', div:not(.jg-spinner)';
22065  };
22066
22067  /**
22068   * @returns {Array} all entries matched by `settings.selector`
22069   */
22070  JustifiedGallery.prototype.getAllEntries = function () {
22071    var selector = this.getSelectorWithoutSpinner();
22072    return this.$gallery.children(selector).toArray();
22073  };
22074
22075  /**
22076   * Update the entries searching it from the justified gallery HTML element
22077   *
22078   * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered)
22079   * @returns {boolean} true if some entries has been founded
22080   */
22081  JustifiedGallery.prototype.updateEntries = function (norewind) {
22082    var newEntries;
22083
22084    if (norewind && this.lastFetchedEntry != null) {
22085      var selector = this.getSelectorWithoutSpinner();
22086      newEntries = $(this.lastFetchedEntry).nextAll(selector).toArray();
22087    } else {
22088      this.entries = [];
22089      newEntries = this.getAllEntries();
22090    }
22091
22092    if (newEntries.length > 0) {
22093
22094      // Sort or randomize
22095      if ($.isFunction(this.settings.sort)) {
22096        newEntries = this.sortArray(newEntries);
22097      } else if (this.settings.randomize) {
22098        newEntries = this.shuffleArray(newEntries);
22099      }
22100      this.lastFetchedEntry = newEntries[newEntries.length - 1];
22101
22102      // Filter
22103      if (this.settings.filter) {
22104        newEntries = this.filterArray(newEntries);
22105      } else {
22106        this.resetFilters(newEntries);
22107      }
22108
22109    }
22110
22111    this.entries = this.entries.concat(newEntries);
22112    return true;
22113  };
22114
22115  /**
22116   * Apply the entries order to the DOM, iterating the entries and appending the images
22117   *
22118   * @param entries the entries that has been modified and that must be re-ordered in the DOM
22119   */
22120  JustifiedGallery.prototype.insertToGallery = function (entries) {
22121    var that = this;
22122    $.each(entries, function () {
22123      $(this).appendTo(that.$gallery);
22124    });
22125  };
22126
22127  /**
22128   * Shuffle the array using the Fisher-Yates shuffle algorithm
22129   *
22130   * @param a the array to shuffle
22131   * @return the shuffled array
22132   */
22133  JustifiedGallery.prototype.shuffleArray = function (a) {
22134    var i, j, temp;
22135    for (i = a.length - 1; i > 0; i--) {
22136      j = Math.floor(Math.random() * (i + 1));
22137      temp = a[i];
22138      a[i] = a[j];
22139      a[j] = temp;
22140    }
22141    this.insertToGallery(a);
22142    return a;
22143  };
22144
22145  /**
22146   * Sort the array using settings.comparator as comparator
22147   *
22148   * @param a the array to sort (it is sorted)
22149   * @return the sorted array
22150   */
22151  JustifiedGallery.prototype.sortArray = function (a) {
22152    a.sort(this.settings.sort);
22153    this.insertToGallery(a);
22154    return a;
22155  };
22156
22157  /**
22158   * Reset the filters removing the 'jg-filtered' class from all the entries
22159   *
22160   * @param a the array to reset
22161   */
22162  JustifiedGallery.prototype.resetFilters = function (a) {
22163    for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered');
22164  };
22165
22166  /**
22167   * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering.
22168   *
22169   * @param a the array to filter
22170   * @return the filtered array
22171   */
22172  JustifiedGallery.prototype.filterArray = function (a) {
22173    var settings = this.settings;
22174    if ($.type(settings.filter) === 'string') {
22175      // Filter only keeping the entries passed in the string
22176      return a.filter(function (el) {
22177        var $el = $(el);
22178        if ($el.is(settings.filter)) {
22179          $el.removeClass('jg-filtered');
22180          return true;
22181        } else {
22182          $el.addClass('jg-filtered').removeClass('jg-visible');
22183          return false;
22184        }
22185      });
22186    } else if ($.isFunction(settings.filter)) {
22187      // Filter using the passed function
22188      var filteredArr = a.filter(settings.filter);
22189      for (var i = 0; i < a.length; i++) {
22190        if (filteredArr.indexOf(a[i]) === -1) {
22191          $(a[i]).addClass('jg-filtered').removeClass('jg-visible');
22192        } else {
22193          $(a[i]).removeClass('jg-filtered');
22194        }
22195      }
22196      return filteredArr;
22197    }
22198  };
22199
22200  /**
22201   * Revert the image src to the default value.
22202   */
22203  JustifiedGallery.prototype.resetImgSrc = function ($img) {
22204    if ($img.data('jg.originalSrcLoc') === 'src') {
22205      $img.attr('src', $img.data('jg.originalSrc'));
22206    } else {
22207      $img.attr('src', '');
22208    }
22209  };
22210
22211  /**
22212   * Destroy the Justified Gallery instance.
22213   *
22214   * It clears all the css properties added in the style attributes. We doesn't backup the original
22215   * values for those css attributes, because it costs (performance) and because in general one
22216   * shouldn't use the style attribute for an uniform set of images (where we suppose the use of
22217   * classes). Creating a backup is also difficult because JG could be called multiple times and
22218   * with different style attributes.
22219   */
22220  JustifiedGallery.prototype.destroy = function () {
22221    clearInterval(this.checkWidthIntervalId);
22222    this.stopImgAnalyzerStarter();
22223
22224    // Get fresh entries list since filtered entries are absent in `this.entries`
22225    $.each(this.getAllEntries(), $.proxy(function (_, entry) {
22226      var $entry = $(entry);
22227
22228      // Reset entry style
22229      $entry.css('width', '');
22230      $entry.css('height', '');
22231      $entry.css('top', '');
22232      $entry.css('left', '');
22233      $entry.data('jg.loaded', undefined);
22234      $entry.removeClass('jg-entry jg-filtered jg-entry-visible');
22235
22236      // Reset image style
22237      var $img = this.imgFromEntry($entry);
22238      if ($img) {
22239        $img.css('width', '');
22240        $img.css('height', '');
22241        $img.css('margin-left', '');
22242        $img.css('margin-top', '');
22243        this.resetImgSrc($img);
22244        $img.data('jg.originalSrc', undefined);
22245        $img.data('jg.originalSrcLoc', undefined);
22246        $img.data('jg.src', undefined);
22247      }
22248
22249      // Remove caption
22250      this.removeCaptionEventsHandlers($entry);
22251      var $caption = this.captionFromEntry($entry);
22252      if ($entry.data('jg.createdCaption')) {
22253        // remove also the caption element (if created by jg)
22254        $entry.data('jg.createdCaption', undefined);
22255        if ($caption !== null) $caption.remove();
22256      } else {
22257        if ($caption !== null) $caption.fadeTo(0, 1);
22258      }
22259
22260    }, this));
22261
22262    this.$gallery.css('height', '');
22263    this.$gallery.removeClass('justified-gallery');
22264    this.$gallery.data('jg.controller', undefined);
22265    this.settings.triggerEvent.call(this, 'jg.destroy');
22266  };
22267
22268  /**
22269   * Analyze the images and builds the rows. It returns if it found an image that is not loaded.
22270   *
22271   * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end
22272   */
22273  JustifiedGallery.prototype.analyzeImages = function (isForResize) {
22274    for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) {
22275      var $entry = $(this.entries[i]);
22276      if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') {
22277        var availableWidth = this.galleryWidth - 2 * this.border - (
22278          (this.buildingRow.entriesBuff.length - 1) * this.settings.margins);
22279        var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height');
22280
22281        this.buildingRow.entriesBuff.push($entry);
22282        this.buildingRow.aspectRatio += imgAspectRatio;
22283        this.buildingRow.width += imgAspectRatio * this.settings.rowHeight;
22284        this.lastAnalyzedIndex = i;
22285
22286        if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) {
22287          this.flushRow(false, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
22288
22289          if (++this.yield.flushed >= this.yield.every) {
22290            this.startImgAnalyzer(isForResize);
22291            return;
22292          }
22293        }
22294      } else if ($entry.data('jg.loaded') !== 'error') {
22295        return;
22296      }
22297    }
22298
22299    // Last row flush (the row is not full)
22300    if (this.buildingRow.entriesBuff.length > 0) {
22301      this.flushRow(true, this.settings.maxRowsCount > 0 && this.rows === this.settings.maxRowsCount);
22302    }
22303
22304    if (this.isSpinnerActive()) {
22305      this.stopLoadingSpinnerAnimation();
22306    }
22307
22308    /* Stop, if there is, the timeout to start the analyzeImages.
22309     This is because an image can be set loaded, and the timeout can be set,
22310     but this image can be analyzed yet.
22311     */
22312    this.stopImgAnalyzerStarter();
22313
22314    this.setGalleryFinalHeight(this.galleryHeightToSet);
22315
22316    //On complete callback
22317    this.settings.triggerEvent.call(this, isForResize ? 'jg.resize' : 'jg.complete');
22318  };
22319
22320  /**
22321   * Stops any ImgAnalyzer starter (that has an assigned timeout)
22322   */
22323  JustifiedGallery.prototype.stopImgAnalyzerStarter = function () {
22324    this.yield.flushed = 0;
22325    if (this.imgAnalyzerTimeout !== null) {
22326      clearTimeout(this.imgAnalyzerTimeout);
22327      this.imgAnalyzerTimeout = null;
22328    }
22329  };
22330
22331  /**
22332   * Starts the image analyzer. It is not immediately called to let the browser to update the view
22333   *
22334   * @param isForResize specifies if the image analyzer must be called for resizing or not
22335   */
22336  JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) {
22337    var that = this;
22338    this.stopImgAnalyzerStarter();
22339    this.imgAnalyzerTimeout = setTimeout(function () {
22340      that.analyzeImages(isForResize);
22341    }, 0.001); // we can't start it immediately due to a IE different behaviour
22342  };
22343
22344  /**
22345   * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property,
22346   * because some browsers, with a 404 set complete = true.
22347   *
22348   * @param imageSrc the image src to load
22349   * @param onLoad callback that is called when the image has been loaded
22350   * @param onError callback that is called in case of an error
22351   */
22352  JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) {
22353    if (!onLoad && !onError) return;
22354
22355    var memImage = new Image();
22356    var $memImage = $(memImage);
22357    if (onLoad) {
22358      $memImage.one('load', function () {
22359        $memImage.off('load error');
22360        onLoad(memImage);
22361      });
22362    }
22363    if (onError) {
22364      $memImage.one('error', function () {
22365        $memImage.off('load error');
22366        onError(memImage);
22367      });
22368    }
22369    memImage.src = imageSrc;
22370  };
22371
22372  /**
22373   * Init of Justified Gallery controlled
22374   * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images)
22375   */
22376  JustifiedGallery.prototype.init = function () {
22377    var imagesToLoad = false, skippedImages = false, that = this;
22378    $.each(this.entries, function (index, entry) {
22379      var $entry = $(entry);
22380      var $image = that.imgFromEntry($entry);
22381
22382      $entry.addClass('jg-entry');
22383
22384      if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') {
22385
22386        // Link Rel global overwrite
22387        if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel);
22388
22389        // Link Target global overwrite
22390        if (that.settings.target !== null) $entry.attr('target', that.settings.target);
22391
22392        if ($image !== null) {
22393
22394          // Image src
22395          var imageSrc = that.extractImgSrcFromImage($image);
22396
22397          /* If we have the height and the width, we don't wait that the image is loaded,
22398             but we start directly with the justification */
22399          if (that.settings.waitThumbnailsLoad === false || !imageSrc) {
22400            var width = parseFloat($image.attr('width'));
22401            var height = parseFloat($image.attr('height'));
22402            if ($image.prop('tagName') === 'svg') {
22403              width = parseFloat($image[0].getBBox().width);
22404              height = parseFloat($image[0].getBBox().height);
22405            }
22406            if (!isNaN(width) && !isNaN(height)) {
22407              $entry.data('jg.width', width);
22408              $entry.data('jg.height', height);
22409              $entry.data('jg.loaded', 'skipped');
22410              skippedImages = true;
22411              that.startImgAnalyzer(false);
22412              return true; // continue
22413            }
22414          }
22415
22416          $entry.data('jg.loaded', false);
22417          imagesToLoad = true;
22418
22419          // Spinner start
22420          if (!that.isSpinnerActive()) that.startLoadingSpinnerAnimation();
22421
22422          that.onImageEvent(imageSrc, function (loadImg) { // image loaded
22423            $entry.data('jg.width', loadImg.width);
22424            $entry.data('jg.height', loadImg.height);
22425            $entry.data('jg.loaded', true);
22426            that.startImgAnalyzer(false);
22427          }, function () { // image load error
22428            $entry.data('jg.loaded', 'error');
22429            that.startImgAnalyzer(false);
22430          });
22431
22432        } else {
22433          $entry.data('jg.loaded', true);
22434          $entry.data('jg.width', $entry.width() | parseFloat($entry.css('width')) | 1);
22435          $entry.data('jg.height', $entry.height() | parseFloat($entry.css('height')) | 1);
22436        }
22437
22438      }
22439
22440    });
22441
22442    if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false);
22443    this.checkWidth();
22444  };
22445
22446  /**
22447   * Checks that it is a valid number. If a string is passed it is converted to a number
22448   *
22449   * @param settingContainer the object that contains the setting (to allow the conversion)
22450   * @param settingName the setting name
22451   */
22452  JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) {
22453    if ($.type(settingContainer[settingName]) === 'string') {
22454      settingContainer[settingName] = parseFloat(settingContainer[settingName]);
22455    }
22456
22457    if ($.type(settingContainer[settingName]) === 'number') {
22458      if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName;
22459    } else {
22460      throw settingName + ' must be a number';
22461    }
22462  };
22463
22464  /**
22465   * Checks the sizeRangeSuffixes and, if necessary, converts
22466   * its keys from string (e.g. old settings with 'lt100') to int.
22467   */
22468  JustifiedGallery.prototype.checkSizeRangesSuffixes = function () {
22469    if ($.type(this.settings.sizeRangeSuffixes) !== 'object') {
22470      throw 'sizeRangeSuffixes must be defined and must be an object';
22471    }
22472
22473    var suffixRanges = [];
22474    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
22475      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx);
22476    }
22477
22478    var newSizeRngSuffixes = { 0: '' };
22479    for (var i = 0; i < suffixRanges.length; i++) {
22480      if ($.type(suffixRanges[i]) === 'string') {
22481        try {
22482          var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10);
22483          newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
22484        } catch (e) {
22485          throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')';
22486        }
22487      } else {
22488        newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]];
22489      }
22490    }
22491
22492    this.settings.sizeRangeSuffixes = newSizeRngSuffixes;
22493  };
22494
22495  /**
22496   * check and convert the maxRowHeight setting
22497   * requires rowHeight to be already set
22498   * TODO: should be always called when only rowHeight is changed
22499   * @return number or null
22500   */
22501  JustifiedGallery.prototype.retrieveMaxRowHeight = function () {
22502    var newMaxRowHeight = null;
22503    var rowHeight = this.settings.rowHeight;
22504
22505    if ($.type(this.settings.maxRowHeight) === 'string') {
22506      if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) {
22507        newMaxRowHeight = rowHeight * parseFloat(this.settings.maxRowHeight.match(/^([0-9]+)%$/)[1]) / 100;
22508      } else {
22509        newMaxRowHeight = parseFloat(this.settings.maxRowHeight);
22510      }
22511    } else if ($.type(this.settings.maxRowHeight) === 'number') {
22512      newMaxRowHeight = this.settings.maxRowHeight;
22513    } else if (this.settings.maxRowHeight === false || this.settings.maxRowHeight == null) {
22514      return null;
22515    } else {
22516      throw 'maxRowHeight must be a number or a percentage';
22517    }
22518
22519    // check if the converted value is not a number
22520    if (isNaN(newMaxRowHeight)) throw 'invalid number for maxRowHeight';
22521
22522    // check values, maxRowHeight must be >= rowHeight
22523    if (newMaxRowHeight < rowHeight) newMaxRowHeight = rowHeight;
22524
22525    return newMaxRowHeight;
22526  };
22527
22528  /**
22529   * Checks the settings
22530   */
22531  JustifiedGallery.prototype.checkSettings = function () {
22532    this.checkSizeRangesSuffixes();
22533
22534    this.checkOrConvertNumber(this.settings, 'rowHeight');
22535    this.checkOrConvertNumber(this.settings, 'margins');
22536    this.checkOrConvertNumber(this.settings, 'border');
22537    this.checkOrConvertNumber(this.settings, 'maxRowsCount');
22538
22539    var lastRowModes = [
22540      'justify',
22541      'nojustify',
22542      'left',
22543      'center',
22544      'right',
22545      'hide'
22546    ];
22547    if (lastRowModes.indexOf(this.settings.lastRow) === -1) {
22548      throw 'lastRow must be one of: ' + lastRowModes.join(', ');
22549    }
22550
22551    this.checkOrConvertNumber(this.settings, 'justifyThreshold');
22552    if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) {
22553      throw 'justifyThreshold must be in the interval [0,1]';
22554    }
22555    if ($.type(this.settings.cssAnimation) !== 'boolean') {
22556      throw 'cssAnimation must be a boolean';
22557    }
22558
22559    if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean';
22560    this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration');
22561
22562    this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity');
22563    if (this.settings.captionSettings.visibleOpacity < 0 ||
22564      this.settings.captionSettings.visibleOpacity > 1) {
22565      throw 'captionSettings.visibleOpacity must be in the interval [0, 1]';
22566    }
22567
22568    this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity');
22569    if (this.settings.captionSettings.nonVisibleOpacity < 0 ||
22570      this.settings.captionSettings.nonVisibleOpacity > 1) {
22571      throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]';
22572    }
22573
22574    this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration');
22575    this.checkOrConvertNumber(this.settings, 'refreshTime');
22576    this.checkOrConvertNumber(this.settings, 'refreshSensitivity');
22577    if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean';
22578    if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string';
22579
22580    if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) {
22581      throw 'sort must be false or a comparison function';
22582    }
22583
22584    if (this.settings.filter !== false && !$.isFunction(this.settings.filter) &&
22585      $.type(this.settings.filter) !== 'string') {
22586      throw 'filter must be false, a string or a filter function';
22587    }
22588  };
22589
22590  /**
22591   * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned.
22592   * @returns {Array} sorted suffix ranges
22593   */
22594  JustifiedGallery.prototype.retrieveSuffixRanges = function () {
22595    var suffixRanges = [];
22596    for (var rangeIdx in this.settings.sizeRangeSuffixes) {
22597      if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10));
22598    }
22599    suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; });
22600    return suffixRanges;
22601  };
22602
22603  /**
22604   * Update the existing settings only changing some of them
22605   *
22606   * @param newSettings the new settings (or a subgroup of them)
22607   */
22608  JustifiedGallery.prototype.updateSettings = function (newSettings) {
22609    // In this case Justified Gallery has been called again changing only some options
22610    this.settings = $.extend({}, this.settings, newSettings);
22611    this.checkSettings();
22612
22613    // As reported in the settings: negative value = same as margins, 0 = disabled
22614    this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins;
22615
22616    this.maxRowHeight = this.retrieveMaxRowHeight();
22617    this.suffixRanges = this.retrieveSuffixRanges();
22618  };
22619
22620  JustifiedGallery.prototype.defaults = {
22621    sizeRangeSuffixes: {}, /* e.g. Flickr configuration
22622        {
22623          100: '_t',  // used when longest is less than 100px
22624          240: '_m',  // used when longest is between 101px and 240px
22625          320: '_n',  // ...
22626          500: '',
22627          640: '_z',
22628          1024: '_b'  // used as else case because it is the last
22629        }
22630    */
22631    thumbnailPath: undefined, /* If defined, sizeRangeSuffixes is not used, and this function is used to determine the
22632    path relative to a specific thumbnail size. The function should accept respectively three arguments:
22633    current path, width and height */
22634    rowHeight: 120, // required? required to be > 0?
22635    maxRowHeight: false, // false or negative value to deactivate. Positive number to express the value in pixels,
22636    // A string '[0-9]+%' to express in percentage (e.g. 300% means that the row height
22637    // can't exceed 3 * rowHeight)
22638    maxRowsCount: 0, // maximum number of rows to be displayed (0 = disabled)
22639    margins: 1,
22640    border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border
22641
22642    lastRow: 'nojustify', // … which is the same as 'left', or can be 'justify', 'center', 'right' or 'hide'
22643
22644    justifyThreshold: 0.90, /* if row width / available space > 0.90 it will be always justified
22645                             * (i.e. lastRow setting is not considered) */
22646    waitThumbnailsLoad: true,
22647    captions: true,
22648    cssAnimation: true,
22649    imagesAnimationDuration: 500, // ignored with css animations
22650    captionSettings: { // ignored with css animations
22651      animationDuration: 500,
22652      visibleOpacity: 0.7,
22653      nonVisibleOpacity: 0.0
22654    },
22655    rel: null, // rewrite the rel of each analyzed links
22656    target: null, // rewrite the target of all links
22657    extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image
22658    refreshTime: 200, // time interval (in ms) to check if the page changes its width
22659    refreshSensitivity: 0, // change in width allowed (in px) without re-building the gallery
22660    randomize: false,
22661    rtl: false, // right-to-left mode
22662    sort: false, /*
22663      - false: to do not sort
22664      - function: to sort them using the function as comparator (see Array.prototype.sort())
22665    */
22666    filter: false, /*
22667      - false, null or undefined: for a disabled filter
22668      - a string: an entry is kept if entry.is(filter string) returns true
22669                  see jQuery's .is() function for further information
22670      - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise.
22671                    It follows the specifications of the Array.prototype.filter() function of JavaScript.
22672    */
22673    selector: 'a', // The selector that is used to know what are the entries of the gallery
22674    imgSelector: '> img, > a > img, > svg, > a > svg', // The selector that is used to know what are the images of each entry
22675    triggerEvent: function (event) { // This is called to trigger events, the default behavior is to call $.trigger
22676      this.$gallery.trigger(event);  // Consider that 'this' is this set to the JustifiedGallery object, so it can
22677    }                                // access to fields such as $gallery, useful to trigger events with jQuery.
22678  };
22679
22680
22681  /**
22682   * Justified Gallery plugin for jQuery
22683   *
22684   * Events
22685   *  - jg.complete : called when all the gallery has been created
22686   *  - jg.resize : called when the gallery has been resized
22687   *  - jg.rowflush : when a new row appears
22688   *
22689   * @param arg the action (or the settings) passed when the plugin is called
22690   * @returns {*} the object itself
22691   */
22692  $.fn.justifiedGallery = function (arg) {
22693    return this.each(function (index, gallery) {
22694
22695      var $gallery = $(gallery);
22696      $gallery.addClass('justified-gallery');
22697
22698      var controller = $gallery.data('jg.controller');
22699      if (typeof controller === 'undefined') {
22700        // Create controller and assign it to the object data
22701        if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') {
22702          if (arg === 'destroy') return; // Just a call to an unexisting object
22703          throw 'The argument must be an object';
22704        }
22705        controller = new JustifiedGallery($gallery, $.extend({}, JustifiedGallery.prototype.defaults, arg));
22706        $gallery.data('jg.controller', controller);
22707      } else if (arg === 'norewind') {
22708        // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row
22709        // ... left to be more readable
22710      } else if (arg === 'destroy') {
22711        controller.destroy();
22712        return;
22713      } else {
22714        // In this case Justified Gallery has been called again changing only some options
22715        controller.updateSettings(arg);
22716        controller.rewind();
22717      }
22718
22719      // Update the entries list
22720      if (!controller.updateEntries(arg === 'norewind')) return;
22721
22722      // Init justified gallery
22723      controller.init();
22724
22725    });
22726  };
22727
22728}));
22729
22730/*!
22731* Customized version of iScroll.js 0.0.1
22732* It fixes bugs affecting its integration with fullpage.js
22733*/
22734/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
22735(function (window, document, Math) {
22736var rAF = window.requestAnimationFrame  ||
22737    window.webkitRequestAnimationFrame  ||
22738    window.mozRequestAnimationFrame     ||
22739    window.oRequestAnimationFrame       ||
22740    window.msRequestAnimationFrame      ||
22741    function (callback) { window.setTimeout(callback, 1000 / 60); };
22742
22743var utils = (function () {
22744    var me = {};
22745
22746    var _elementStyle = document.createElement('div').style;
22747    var _vendor = (function () {
22748        var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
22749            transform,
22750            i = 0,
22751            l = vendors.length;
22752
22753        for ( ; i < l; i++ ) {
22754            transform = vendors[i] + 'ransform';
22755            if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
22756        }
22757
22758        return false;
22759    })();
22760
22761    function _prefixStyle (style) {
22762        if ( _vendor === false ) return false;
22763        if ( _vendor === '' ) return style;
22764        return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
22765    }
22766
22767    me.getTime = Date.now || function getTime () { return new Date().getTime(); };
22768
22769    me.extend = function (target, obj) {
22770        for ( var i in obj ) {
22771            target[i] = obj[i];
22772        }
22773    };
22774
22775    me.addEvent = function (el, type, fn, capture) {
22776        el.addEventListener(type, fn, !!capture);
22777    };
22778
22779    me.removeEvent = function (el, type, fn, capture) {
22780        el.removeEventListener(type, fn, !!capture);
22781    };
22782
22783    me.prefixPointerEvent = function (pointerEvent) {
22784        return window.MSPointerEvent ?
22785            'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
22786            pointerEvent;
22787    };
22788
22789    me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
22790        var distance = current - start,
22791            speed = Math.abs(distance) / time,
22792            destination,
22793            duration;
22794
22795        deceleration = deceleration === undefined ? 0.0006 : deceleration;
22796
22797        destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
22798        duration = speed / deceleration;
22799
22800        if ( destination < lowerMargin ) {
22801            destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
22802            distance = Math.abs(destination - current);
22803            duration = distance / speed;
22804        } else if ( destination > 0 ) {
22805            destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
22806            distance = Math.abs(current) + destination;
22807            duration = distance / speed;
22808        }
22809
22810        return {
22811            destination: Math.round(destination),
22812            duration: duration
22813        };
22814    };
22815
22816    var _transform = _prefixStyle('transform');
22817
22818    me.extend(me, {
22819        hasTransform: _transform !== false,
22820        hasPerspective: _prefixStyle('perspective') in _elementStyle,
22821        hasTouch: 'ontouchstart' in window,
22822        hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
22823        hasTransition: _prefixStyle('transition') in _elementStyle
22824    });
22825
22826    /*
22827    This should find all Android browsers lower than build 535.19 (both stock browser and webview)
22828    - galaxy S2 is ok
22829    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
22830    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22831   - galaxy S3 is badAndroid (stock brower, webview)
22832     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22833   - galaxy S4 is badAndroid (stock brower, webview)
22834     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
22835   - galaxy S5 is OK
22836     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
22837   - galaxy S6 is OK
22838     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
22839  */
22840    me.isBadAndroid = (function() {
22841        var appVersion = window.navigator.appVersion;
22842        // Android browser is not a chrome browser.
22843        if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
22844            var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
22845            if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
22846                return parseFloat(safariVersion[1]) < 535.19;
22847            } else {
22848                return true;
22849            }
22850        } else {
22851            return false;
22852        }
22853    })();
22854
22855    me.extend(me.style = {}, {
22856        transform: _transform,
22857        transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
22858        transitionDuration: _prefixStyle('transitionDuration'),
22859        transitionDelay: _prefixStyle('transitionDelay'),
22860        transformOrigin: _prefixStyle('transformOrigin')
22861    });
22862
22863    me.hasClass = function (e, c) {
22864        var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
22865        return re.test(e.className);
22866    };
22867
22868    me.addClass = function (e, c) {
22869        if ( me.hasClass(e, c) ) {
22870            return;
22871        }
22872
22873        var newclass = e.className.split(' ');
22874        newclass.push(c);
22875        e.className = newclass.join(' ');
22876    };
22877
22878    me.removeClass = function (e, c) {
22879        if ( !me.hasClass(e, c) ) {
22880            return;
22881        }
22882
22883        var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
22884        e.className = e.className.replace(re, ' ');
22885    };
22886
22887    me.offset = function (el) {
22888        var left = -el.offsetLeft,
22889            top = -el.offsetTop;
22890
22891        // jshint -W084
22892        while (el = el.offsetParent) {
22893            left -= el.offsetLeft;
22894            top -= el.offsetTop;
22895        }
22896        // jshint +W084
22897
22898        return {
22899            left: left,
22900            top: top
22901        };
22902    };
22903
22904    me.preventDefaultException = function (el, exceptions) {
22905        for ( var i in exceptions ) {
22906            if ( exceptions[i].test(el[i]) ) {
22907                return true;
22908            }
22909        }
22910
22911        return false;
22912    };
22913
22914    me.extend(me.eventType = {}, {
22915        touchstart: 1,
22916        touchmove: 1,
22917        touchend: 1,
22918
22919        mousedown: 2,
22920        mousemove: 2,
22921        mouseup: 2,
22922
22923        pointerdown: 3,
22924        pointermove: 3,
22925        pointerup: 3,
22926
22927        MSPointerDown: 3,
22928        MSPointerMove: 3,
22929        MSPointerUp: 3
22930    });
22931
22932    me.extend(me.ease = {}, {
22933        quadratic: {
22934            style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
22935            fn: function (k) {
22936                return k * ( 2 - k );
22937            }
22938        },
22939        circular: {
22940            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)
22941            fn: function (k) {
22942                return Math.sqrt( 1 - ( --k * k ) );
22943            }
22944        },
22945        back: {
22946            style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
22947            fn: function (k) {
22948                var b = 4;
22949                return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
22950            }
22951        },
22952        bounce: {
22953            style: '',
22954            fn: function (k) {
22955                if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
22956                    return 7.5625 * k * k;
22957                } else if ( k < ( 2 / 2.75 ) ) {
22958                    return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
22959                } else if ( k < ( 2.5 / 2.75 ) ) {
22960                    return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
22961                } else {
22962                    return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
22963                }
22964            }
22965        },
22966        elastic: {
22967            style: '',
22968            fn: function (k) {
22969                var f = 0.22,
22970                    e = 0.4;
22971
22972                if ( k === 0 ) { return 0; }
22973                if ( k == 1 ) { return 1; }
22974
22975                return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
22976            }
22977        }
22978    });
22979
22980    me.tap = function (e, eventName) {
22981        var ev = document.createEvent('Event');
22982        ev.initEvent(eventName, true, true);
22983        ev.pageX = e.pageX;
22984        ev.pageY = e.pageY;
22985        e.target.dispatchEvent(ev);
22986    };
22987
22988    me.click = function (e) {
22989        var target = e.target,
22990            ev;
22991
22992        if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
22993            // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent
22994            // initMouseEvent is deprecated.
22995            ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');
22996            ev.initEvent('click', true, true);
22997            ev.view = e.view || window;
22998            ev.detail = 1;
22999            ev.screenX = target.screenX || 0;
23000            ev.screenY = target.screenY || 0;
23001            ev.clientX = target.clientX || 0;
23002            ev.clientY = target.clientY || 0;
23003            ev.ctrlKey = !!e.ctrlKey;
23004            ev.altKey = !!e.altKey;
23005            ev.shiftKey = !!e.shiftKey;
23006            ev.metaKey = !!e.metaKey;
23007            ev.button = 0;
23008            ev.relatedTarget = null;
23009            ev._constructed = true;
23010            target.dispatchEvent(ev);
23011        }
23012    };
23013
23014    return me;
23015})();
23016function IScroll (el, options) {
23017    this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
23018    this.scroller = this.wrapper.children[0];
23019    this.scrollerStyle = this.scroller.style;       // cache style for better performance
23020
23021    this.options = {
23022
23023        resizeScrollbars: true,
23024
23025        mouseWheelSpeed: 20,
23026
23027        snapThreshold: 0.334,
23028
23029// INSERT POINT: OPTIONS
23030        disablePointer : !utils.hasPointer,
23031        disableTouch : utils.hasPointer || !utils.hasTouch,
23032        disableMouse : utils.hasPointer || utils.hasTouch,
23033        startX: 0,
23034        startY: 0,
23035        scrollY: true,
23036        directionLockThreshold: 5,
23037        momentum: true,
23038
23039        bounce: true,
23040        bounceTime: 600,
23041        bounceEasing: '',
23042
23043        preventDefault: true,
23044        preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|LABEL)$/ },
23045
23046        HWCompositing: true,
23047        useTransition: true,
23048        useTransform: true,
23049        bindToWrapper: typeof window.onmousedown === "undefined"
23050    };
23051
23052    for ( var i in options ) {
23053        this.options[i] = options[i];
23054    }
23055
23056    // Normalize options
23057    this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
23058
23059    this.options.useTransition = utils.hasTransition && this.options.useTransition;
23060    this.options.useTransform = utils.hasTransform && this.options.useTransform;
23061
23062    this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
23063    this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
23064
23065    // If you want eventPassthrough I have to lock one of the axes
23066    this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
23067    this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
23068
23069    // With eventPassthrough we also need lockDirection mechanism
23070    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
23071    this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
23072
23073    this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
23074
23075    this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
23076
23077    if ( this.options.tap === true ) {
23078        this.options.tap = 'tap';
23079    }
23080
23081    // https://github.com/cubiq/iscroll/issues/1029
23082    if (!this.options.useTransition && !this.options.useTransform) {
23083        if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {
23084            this.scrollerStyle.position = "relative";
23085        }
23086    }
23087
23088    if ( this.options.shrinkScrollbars == 'scale' ) {
23089        this.options.useTransition = false;
23090    }
23091
23092    this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
23093
23094// INSERT POINT: NORMALIZATION
23095
23096    // Some defaults
23097    this.x = 0;
23098    this.y = 0;
23099    this.directionX = 0;
23100    this.directionY = 0;
23101    this._events = {};
23102
23103// INSERT POINT: DEFAULTS
23104
23105    this._init();
23106    this.refresh();
23107
23108    this.scrollTo(this.options.startX, this.options.startY);
23109    this.enable();
23110}
23111
23112IScroll.prototype = {
23113    version: '5.2.0',
23114
23115    _init: function () {
23116        this._initEvents();
23117
23118        if ( this.options.scrollbars || this.options.indicators ) {
23119            this._initIndicators();
23120        }
23121
23122        if ( this.options.mouseWheel ) {
23123            this._initWheel();
23124        }
23125
23126        if ( this.options.snap ) {
23127            this._initSnap();
23128        }
23129
23130        if ( this.options.keyBindings ) {
23131            this._initKeys();
23132        }
23133
23134// INSERT POINT: _init
23135
23136    },
23137
23138    destroy: function () {
23139        this._initEvents(true);
23140        clearTimeout(this.resizeTimeout);
23141        this.resizeTimeout = null;
23142        this._execEvent('destroy');
23143    },
23144
23145    _transitionEnd: function (e) {
23146        if ( e.target != this.scroller || !this.isInTransition ) {
23147            return;
23148        }
23149
23150        this._transitionTime();
23151        if ( !this.resetPosition(this.options.bounceTime) ) {
23152            this.isInTransition = false;
23153            this._execEvent('scrollEnd');
23154        }
23155    },
23156
23157    _start: function (e) {
23158        // React to left mouse button only
23159        if ( utils.eventType[e.type] != 1 ) {
23160          // for button property
23161          // http://unixpapa.com/js/mouse.html
23162          var button;
23163        if (!e.which) {
23164          /* IE case */
23165          button = (e.button < 2) ? 0 :
23166                   ((e.button == 4) ? 1 : 2);
23167        } else {
23168          /* All others */
23169          button = e.button;
23170        }
23171            if ( button !== 0 ) {
23172                return;
23173            }
23174        }
23175
23176        if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
23177            return;
23178        }
23179
23180        if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
23181            e.preventDefault();
23182        }
23183
23184        var point = e.touches ? e.touches[0] : e,
23185            pos;
23186
23187        this.initiated  = utils.eventType[e.type];
23188        this.moved      = false;
23189        this.distX      = 0;
23190        this.distY      = 0;
23191        this.directionX = 0;
23192        this.directionY = 0;
23193        this.directionLocked = 0;
23194
23195        this.startTime = utils.getTime();
23196
23197        if ( this.options.useTransition && this.isInTransition ) {
23198            this._transitionTime();
23199            this.isInTransition = false;
23200            pos = this.getComputedPosition();
23201            this._translate(Math.round(pos.x), Math.round(pos.y));
23202            this._execEvent('scrollEnd');
23203        } else if ( !this.options.useTransition && this.isAnimating ) {
23204            this.isAnimating = false;
23205            this._execEvent('scrollEnd');
23206        }
23207
23208        this.startX    = this.x;
23209        this.startY    = this.y;
23210        this.absStartX = this.x;
23211        this.absStartY = this.y;
23212        this.pointX    = point.pageX;
23213        this.pointY    = point.pageY;
23214
23215        this._execEvent('beforeScrollStart');
23216    },
23217
23218    _move: function (e) {
23219        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
23220            return;
23221        }
23222
23223        if ( this.options.preventDefault ) {    // increases performance on Android? TODO: check!
23224            e.preventDefault();
23225        }
23226
23227        var point       = e.touches ? e.touches[0] : e,
23228            deltaX      = point.pageX - this.pointX,
23229            deltaY      = point.pageY - this.pointY,
23230            timestamp   = utils.getTime(),
23231            newX, newY,
23232            absDistX, absDistY;
23233
23234        this.pointX     = point.pageX;
23235        this.pointY     = point.pageY;
23236
23237        this.distX      += deltaX;
23238        this.distY      += deltaY;
23239        absDistX        = Math.abs(this.distX);
23240        absDistY        = Math.abs(this.distY);
23241
23242        // We need to move at least 10 pixels for the scrolling to initiate
23243        if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
23244            return;
23245        }
23246
23247        // If you are scrolling in one direction lock the other
23248        if ( !this.directionLocked && !this.options.freeScroll ) {
23249            if ( absDistX > absDistY + this.options.directionLockThreshold ) {
23250                this.directionLocked = 'h';     // lock horizontally
23251            } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
23252                this.directionLocked = 'v';     // lock vertically
23253            } else {
23254                this.directionLocked = 'n';     // no lock
23255            }
23256        }
23257
23258        if ( this.directionLocked == 'h' ) {
23259            if ( this.options.eventPassthrough == 'vertical' ) {
23260                e.preventDefault();
23261            } else if ( this.options.eventPassthrough == 'horizontal' ) {
23262                this.initiated = false;
23263                return;
23264            }
23265
23266            deltaY = 0;
23267        } else if ( this.directionLocked == 'v' ) {
23268            if ( this.options.eventPassthrough == 'horizontal' ) {
23269                e.preventDefault();
23270            } else if ( this.options.eventPassthrough == 'vertical' ) {
23271                this.initiated = false;
23272                return;
23273            }
23274
23275            deltaX = 0;
23276        }
23277
23278        deltaX = this.hasHorizontalScroll ? deltaX : 0;
23279        deltaY = this.hasVerticalScroll ? deltaY : 0;
23280
23281        newX = this.x + deltaX;
23282        newY = this.y + deltaY;
23283
23284        // Slow down if outside of the boundaries
23285        if ( newX > 0 || newX < this.maxScrollX ) {
23286            newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
23287        }
23288        if ( newY > 0 || newY < this.maxScrollY ) {
23289            newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
23290        }
23291
23292        this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
23293        this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
23294
23295        if ( !this.moved ) {
23296            this._execEvent('scrollStart');
23297        }
23298
23299        this.moved = true;
23300
23301        this._translate(newX, newY);
23302
23303/* REPLACE START: _move */
23304
23305        if ( timestamp - this.startTime > 300 ) {
23306            this.startTime = timestamp;
23307            this.startX = this.x;
23308            this.startY = this.y;
23309        }
23310
23311/* REPLACE END: _move */
23312
23313    },
23314
23315    _end: function (e) {
23316        if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
23317            return;
23318        }
23319
23320        if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
23321            e.preventDefault();
23322        }
23323
23324        var point = e.changedTouches ? e.changedTouches[0] : e,
23325            momentumX,
23326            momentumY,
23327            duration = utils.getTime() - this.startTime,
23328            newX = Math.round(this.x),
23329            newY = Math.round(this.y),
23330            distanceX = Math.abs(newX - this.startX),
23331            distanceY = Math.abs(newY - this.startY),
23332            time = 0,
23333            easing = '';
23334
23335        this.isInTransition = 0;
23336        this.initiated = 0;
23337        this.endTime = utils.getTime();
23338
23339        // reset if we are outside of the boundaries
23340        if ( this.resetPosition(this.options.bounceTime) ) {
23341            return;
23342        }
23343
23344        this.scrollTo(newX, newY);  // ensures that the last position is rounded
23345
23346        // we scrolled less than 10 pixels
23347        if ( !this.moved ) {
23348            if ( this.options.tap ) {
23349                utils.tap(e, this.options.tap);
23350            }
23351
23352            if ( this.options.click ) {
23353                utils.click(e);
23354            }
23355
23356            this._execEvent('scrollCancel');
23357            return;
23358        }
23359
23360        if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
23361            this._execEvent('flick');
23362            return;
23363        }
23364
23365        // start momentum animation if needed
23366        if ( this.options.momentum && duration < 300 ) {
23367            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 };
23368            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 };
23369            newX = momentumX.destination;
23370            newY = momentumY.destination;
23371            time = Math.max(momentumX.duration, momentumY.duration);
23372            this.isInTransition = 1;
23373        }
23374
23375
23376        if ( this.options.snap ) {
23377            var snap = this._nearestSnap(newX, newY);
23378            this.currentPage = snap;
23379            time = this.options.snapSpeed || Math.max(
23380                    Math.max(
23381                        Math.min(Math.abs(newX - snap.x), 1000),
23382                        Math.min(Math.abs(newY - snap.y), 1000)
23383                    ), 300);
23384            newX = snap.x;
23385            newY = snap.y;
23386
23387            this.directionX = 0;
23388            this.directionY = 0;
23389            easing = this.options.bounceEasing;
23390        }
23391
23392// INSERT POINT: _end
23393
23394        if ( newX != this.x || newY != this.y ) {
23395            // change easing function when scroller goes out of the boundaries
23396            if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
23397                easing = utils.ease.quadratic;
23398            }
23399
23400            this.scrollTo(newX, newY, time, easing);
23401            return;
23402        }
23403
23404        this._execEvent('scrollEnd');
23405    },
23406
23407    _resize: function () {
23408        var that = this;
23409
23410        clearTimeout(this.resizeTimeout);
23411
23412        this.resizeTimeout = setTimeout(function () {
23413            that.refresh();
23414        }, this.options.resizePolling);
23415    },
23416
23417    resetPosition: function (time) {
23418        var x = this.x,
23419            y = this.y;
23420
23421        time = time || 0;
23422
23423        if ( !this.hasHorizontalScroll || this.x > 0 ) {
23424            x = 0;
23425        } else if ( this.x < this.maxScrollX ) {
23426            x = this.maxScrollX;
23427        }
23428
23429        if ( !this.hasVerticalScroll || this.y > 0 ) {
23430            y = 0;
23431        } else if ( this.y < this.maxScrollY ) {
23432            y = this.maxScrollY;
23433        }
23434
23435        if ( x == this.x && y == this.y ) {
23436            return false;
23437        }
23438
23439        this.scrollTo(x, y, time, this.options.bounceEasing);
23440
23441        return true;
23442    },
23443
23444    disable: function () {
23445        this.enabled = false;
23446    },
23447
23448    enable: function () {
23449        this.enabled = true;
23450    },
23451
23452    refresh: function () {
23453        var rf = this.wrapper.offsetHeight;     // Force reflow
23454
23455        this.wrapperWidth   = this.wrapper.clientWidth;
23456        this.wrapperHeight  = this.wrapper.clientHeight;
23457
23458/* REPLACE START: refresh */
23459
23460        this.scrollerWidth  = this.scroller.offsetWidth;
23461        this.scrollerHeight = this.scroller.offsetHeight;
23462
23463        this.maxScrollX     = this.wrapperWidth - this.scrollerWidth;
23464        this.maxScrollY     = this.wrapperHeight - this.scrollerHeight;
23465
23466/* REPLACE END: refresh */
23467
23468        this.hasHorizontalScroll    = this.options.scrollX && this.maxScrollX < 0;
23469        this.hasVerticalScroll      = this.options.scrollY && this.maxScrollY < 0;
23470
23471        if ( !this.hasHorizontalScroll ) {
23472            this.maxScrollX = 0;
23473            this.scrollerWidth = this.wrapperWidth;
23474        }
23475
23476        if ( !this.hasVerticalScroll ) {
23477            this.maxScrollY = 0;
23478            this.scrollerHeight = this.wrapperHeight;
23479        }
23480
23481        this.endTime = 0;
23482        this.directionX = 0;
23483        this.directionY = 0;
23484
23485        this.wrapperOffset = utils.offset(this.wrapper);
23486
23487        this._execEvent('refresh');
23488
23489        this.resetPosition();
23490
23491// INSERT POINT: _refresh
23492
23493    },
23494
23495
23496    on: function (type, fn) {
23497        if ( !this._events[type] ) {
23498            this._events[type] = [];
23499        }
23500
23501        this._events[type].push(fn);
23502    },
23503
23504    off: function (type, fn) {
23505        if ( !this._events[type] ) {
23506            return;
23507        }
23508
23509        var index = this._events[type].indexOf(fn);
23510
23511        if ( index > -1 ) {
23512            this._events[type].splice(index, 1);
23513        }
23514    },
23515
23516    _execEvent: function (type) {
23517        if ( !this._events[type] ) {
23518            return;
23519        }
23520
23521        var i = 0,
23522            l = this._events[type].length;
23523
23524        if ( !l ) {
23525            return;
23526        }
23527
23528        for ( ; i < l; i++ ) {
23529            this._events[type][i].apply(this, [].slice.call(arguments, 1));
23530        }
23531    },
23532
23533    scrollBy: function (x, y, time, easing) {
23534        x = this.x + x;
23535        y = this.y + y;
23536        time = time || 0;
23537
23538        this.scrollTo(x, y, time, easing);
23539    },
23540
23541    scrollTo: function (x, y, time, easing) {
23542        easing = easing || utils.ease.circular;
23543
23544        this.isInTransition = this.options.useTransition && time > 0;
23545        var transitionType = this.options.useTransition && easing.style;
23546        if ( !time || transitionType ) {
23547                if(transitionType) {
23548                    this._transitionTimingFunction(easing.style);
23549                    this._transitionTime(time);
23550                }
23551            this._translate(x, y);
23552        } else {
23553            this._animate(x, y, time, easing.fn);
23554        }
23555    },
23556
23557    scrollToElement: function (el, time, offsetX, offsetY, easing) {
23558        el = el.nodeType ? el : this.scroller.querySelector(el);
23559
23560        if ( !el ) {
23561            return;
23562        }
23563
23564        var pos = utils.offset(el);
23565
23566        pos.left -= this.wrapperOffset.left;
23567        pos.top  -= this.wrapperOffset.top;
23568
23569        // if offsetX/Y are true we center the element to the screen
23570        if ( offsetX === true ) {
23571            offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
23572        }
23573        if ( offsetY === true ) {
23574            offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
23575        }
23576
23577        pos.left -= offsetX || 0;
23578        pos.top  -= offsetY || 0;
23579
23580        pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
23581        pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;
23582
23583        time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
23584
23585        this.scrollTo(pos.left, pos.top, time, easing);
23586    },
23587
23588    _transitionTime: function (time) {
23589        if (!this.options.useTransition) {
23590            return;
23591        }
23592        time = time || 0;
23593        var durationProp = utils.style.transitionDuration;
23594        if(!durationProp) {
23595            return;
23596        }
23597
23598        this.scrollerStyle[durationProp] = time + 'ms';
23599
23600        if ( !time && utils.isBadAndroid ) {
23601            this.scrollerStyle[durationProp] = '0.0001ms';
23602            // remove 0.0001ms
23603            var self = this;
23604            rAF(function() {
23605                if(self.scrollerStyle[durationProp] === '0.0001ms') {
23606                    self.scrollerStyle[durationProp] = '0s';
23607                }
23608            });
23609        }
23610
23611
23612        if ( this.indicators ) {
23613            for ( var i = this.indicators.length; i--; ) {
23614                this.indicators[i].transitionTime(time);
23615            }
23616        }
23617
23618
23619// INSERT POINT: _transitionTime
23620
23621    },
23622
23623    _transitionTimingFunction: function (easing) {
23624        this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
23625
23626
23627        if ( this.indicators ) {
23628            for ( var i = this.indicators.length; i--; ) {
23629                this.indicators[i].transitionTimingFunction(easing);
23630            }
23631        }
23632
23633
23634// INSERT POINT: _transitionTimingFunction
23635
23636    },
23637
23638    _translate: function (x, y) {
23639        //Uncode addition
23640        if ( (" " + this.wrapper.className + " ").replace(/[\n\t]/g, " ").indexOf(" no-scrolloverflow ") > -1 )
23641            return false;
23642
23643        if ( this.options.useTransform ) {
23644
23645/* REPLACE START: _translate */
23646
23647            this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
23648
23649/* REPLACE END: _translate */
23650
23651        } else {
23652            x = Math.round(x);
23653            y = Math.round(y);
23654            this.scrollerStyle.left = x + 'px';
23655            this.scrollerStyle.top = y + 'px';
23656        }
23657
23658        this.x = x;
23659        this.y = y;
23660
23661
23662        if ( this.indicators ) {
23663            for ( var i = this.indicators.length; i--; ) {
23664                this.indicators[i].updatePosition();
23665            }
23666        }
23667
23668        //Uncode addition
23669        var uncodevent = new CustomEvent('fp-slide-scroll');
23670        window.dispatchEvent(uncodevent);
23671
23672// INSERT POINT: _translate
23673
23674    },
23675
23676    _initEvents: function (remove) {
23677        var eventType = remove ? utils.removeEvent : utils.addEvent,
23678            target = this.options.bindToWrapper ? this.wrapper : window;
23679
23680        eventType(window, 'orientationchange', this);
23681        eventType(window, 'resize', this);
23682
23683        if ( this.options.click ) {
23684            eventType(this.wrapper, 'click', this, true);
23685        }
23686
23687        if ( !this.options.disableMouse ) {
23688            eventType(this.wrapper, 'mousedown', this);
23689            eventType(target, 'mousemove', this);
23690            eventType(target, 'mousecancel', this);
23691            eventType(target, 'mouseup', this);
23692        }
23693
23694        if ( utils.hasPointer && !this.options.disablePointer ) {
23695            eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
23696            eventType(target, utils.prefixPointerEvent('pointermove'), this);
23697            eventType(target, utils.prefixPointerEvent('pointercancel'), this);
23698            eventType(target, utils.prefixPointerEvent('pointerup'), this);
23699        }
23700
23701        if ( utils.hasTouch && !this.options.disableTouch ) {
23702            eventType(this.wrapper, 'touchstart', this);
23703            eventType(target, 'touchmove', this);
23704            eventType(target, 'touchcancel', this);
23705            eventType(target, 'touchend', this);
23706        }
23707
23708        eventType(this.scroller, 'transitionend', this);
23709        eventType(this.scroller, 'webkitTransitionEnd', this);
23710        eventType(this.scroller, 'oTransitionEnd', this);
23711        eventType(this.scroller, 'MSTransitionEnd', this);
23712    },
23713
23714    getComputedPosition: function () {
23715        var matrix = window.getComputedStyle(this.scroller, null),
23716            x, y;
23717
23718        if ( this.options.useTransform ) {
23719            matrix = matrix[utils.style.transform].split(')')[0].split(', ');
23720            x = +(matrix[12] || matrix[4]);
23721            y = +(matrix[13] || matrix[5]);
23722        } else {
23723            x = +matrix.left.replace(/[^-\d.]/g, '');
23724            y = +matrix.top.replace(/[^-\d.]/g, '');
23725        }
23726
23727        return { x: x, y: y };
23728    },
23729    _initIndicators: function () {
23730        var interactive = this.options.interactiveScrollbars,
23731            customStyle = typeof this.options.scrollbars != 'string',
23732            indicators = [],
23733            indicator;
23734
23735        var that = this;
23736
23737        this.indicators = [];
23738
23739        if ( this.options.scrollbars ) {
23740            // Vertical scrollbar
23741            if ( this.options.scrollY ) {
23742                indicator = {
23743                    el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
23744                    interactive: interactive,
23745                    defaultScrollbars: true,
23746                    customStyle: customStyle,
23747                    resize: this.options.resizeScrollbars,
23748                    shrink: this.options.shrinkScrollbars,
23749                    fade: this.options.fadeScrollbars,
23750                    listenX: false
23751                };
23752
23753                this.wrapper.appendChild(indicator.el);
23754                indicators.push(indicator);
23755            }
23756
23757            // Horizontal scrollbar
23758            if ( this.options.scrollX ) {
23759                indicator = {
23760                    el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
23761                    interactive: interactive,
23762                    defaultScrollbars: true,
23763                    customStyle: customStyle,
23764                    resize: this.options.resizeScrollbars,
23765                    shrink: this.options.shrinkScrollbars,
23766                    fade: this.options.fadeScrollbars,
23767                    listenY: false
23768                };
23769
23770                this.wrapper.appendChild(indicator.el);
23771                indicators.push(indicator);
23772            }
23773        }
23774
23775        if ( this.options.indicators ) {
23776            // TODO: check concat compatibility
23777            indicators = indicators.concat(this.options.indicators);
23778        }
23779
23780        for ( var i = indicators.length; i--; ) {
23781            this.indicators.push( new Indicator(this, indicators[i]) );
23782        }
23783
23784        // TODO: check if we can use array.map (wide compatibility and performance issues)
23785        function _indicatorsMap (fn) {
23786            if (that.indicators) {
23787                for ( var i = that.indicators.length; i--; ) {
23788                    fn.call(that.indicators[i]);
23789                }
23790            }
23791        }
23792
23793        if ( this.options.fadeScrollbars ) {
23794            this.on('scrollEnd', function () {
23795                _indicatorsMap(function () {
23796                    this.fade();
23797                });
23798            });
23799
23800            this.on('scrollCancel', function () {
23801                _indicatorsMap(function () {
23802                    this.fade();
23803                });
23804            });
23805
23806            this.on('scrollStart', function () {
23807                _indicatorsMap(function () {
23808                    this.fade(1);
23809                });
23810            });
23811
23812            this.on('beforeScrollStart', function () {
23813                _indicatorsMap(function () {
23814                    this.fade(1, true);
23815                });
23816            });
23817        }
23818
23819
23820        this.on('refresh', function () {
23821            _indicatorsMap(function () {
23822                this.refresh();
23823            });
23824        });
23825
23826        this.on('destroy', function () {
23827            _indicatorsMap(function () {
23828                this.destroy();
23829            });
23830
23831            delete this.indicators;
23832        });
23833    },
23834
23835    _initWheel: function () {
23836        utils.addEvent(this.wrapper, 'wheel', this);
23837        utils.addEvent(this.wrapper, 'mousewheel', this);
23838        utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
23839
23840        this.on('destroy', function () {
23841            clearTimeout(this.wheelTimeout);
23842            this.wheelTimeout = null;
23843            utils.removeEvent(this.wrapper, 'wheel', this);
23844            utils.removeEvent(this.wrapper, 'mousewheel', this);
23845            utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
23846        });
23847    },
23848
23849    _wheel: function (e) {
23850        if ( !this.enabled ) {
23851            return;
23852        }
23853
23854        var wheelDeltaX, wheelDeltaY,
23855            newX, newY,
23856            that = this;
23857
23858        if ( this.wheelTimeout === undefined ) {
23859            that._execEvent('scrollStart');
23860        }
23861
23862        // Execute the scrollEnd event after 400ms the wheel stopped scrolling
23863        clearTimeout(this.wheelTimeout);
23864        this.wheelTimeout = setTimeout(function () {
23865            if(!that.options.snap) {
23866                that._execEvent('scrollEnd');
23867            }
23868            that.wheelTimeout = undefined;
23869        }, 400);
23870
23871        if ( 'deltaX' in e ) {
23872            if (e.deltaMode === 1) {
23873                wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
23874                wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
23875            } else {
23876                wheelDeltaX = -e.deltaX;
23877                wheelDeltaY = -e.deltaY;
23878            }
23879        } else if ( 'wheelDeltaX' in e ) {
23880            wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
23881            wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
23882        } else if ( 'wheelDelta' in e ) {
23883            wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
23884        } else if ( 'detail' in e ) {
23885            wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
23886        } else {
23887            return;
23888        }
23889
23890        wheelDeltaX *= this.options.invertWheelDirection;
23891        wheelDeltaY *= this.options.invertWheelDirection;
23892
23893        if ( !this.hasVerticalScroll ) {
23894            wheelDeltaX = wheelDeltaY;
23895            wheelDeltaY = 0;
23896        }
23897
23898        if ( this.options.snap ) {
23899            newX = this.currentPage.pageX;
23900            newY = this.currentPage.pageY;
23901
23902            if ( wheelDeltaX > 0 ) {
23903                newX--;
23904            } else if ( wheelDeltaX < 0 ) {
23905                newX++;
23906            }
23907
23908            if ( wheelDeltaY > 0 ) {
23909                newY--;
23910            } else if ( wheelDeltaY < 0 ) {
23911                newY++;
23912            }
23913
23914            this.goToPage(newX, newY);
23915
23916            return;
23917        }
23918
23919        newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
23920        newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
23921
23922        this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
23923        this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
23924
23925        if ( newX > 0 ) {
23926            newX = 0;
23927        } else if ( newX < this.maxScrollX ) {
23928            newX = this.maxScrollX;
23929        }
23930
23931        if ( newY > 0 ) {
23932            newY = 0;
23933        } else if ( newY < this.maxScrollY ) {
23934            newY = this.maxScrollY;
23935        }
23936
23937        this.scrollTo(newX, newY, 0);
23938
23939// INSERT POINT: _wheel
23940    },
23941
23942    _initSnap: function () {
23943        this.currentPage = {};
23944
23945        if ( typeof this.options.snap == 'string' ) {
23946            this.options.snap = this.scroller.querySelectorAll(this.options.snap);
23947        }
23948
23949        this.on('refresh', function () {
23950            var i = 0, l,
23951                m = 0, n,
23952                cx, cy,
23953                x = 0, y,
23954                stepX = this.options.snapStepX || this.wrapperWidth,
23955                stepY = this.options.snapStepY || this.wrapperHeight,
23956                el;
23957
23958            this.pages = [];
23959
23960            if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
23961                return;
23962            }
23963
23964            if ( this.options.snap === true ) {
23965                cx = Math.round( stepX / 2 );
23966                cy = Math.round( stepY / 2 );
23967
23968                while ( x > -this.scrollerWidth ) {
23969                    this.pages[i] = [];
23970                    l = 0;
23971                    y = 0;
23972
23973                    while ( y > -this.scrollerHeight ) {
23974                        this.pages[i][l] = {
23975                            x: Math.max(x, this.maxScrollX),
23976                            y: Math.max(y, this.maxScrollY),
23977                            width: stepX,
23978                            height: stepY,
23979                            cx: x - cx,
23980                            cy: y - cy
23981                        };
23982
23983                        y -= stepY;
23984                        l++;
23985                    }
23986
23987                    x -= stepX;
23988                    i++;
23989                }
23990            } else {
23991                el = this.options.snap;
23992                l = el.length;
23993                n = -1;
23994
23995                for ( ; i < l; i++ ) {
23996                    if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
23997                        m = 0;
23998                        n++;
23999                    }
24000
24001                    if ( !this.pages[m] ) {
24002                        this.pages[m] = [];
24003                    }
24004
24005                    x = Math.max(-el[i].offsetLeft, this.maxScrollX);
24006                    y = Math.max(-el[i].offsetTop, this.maxScrollY);
24007                    cx = x - Math.round(el[i].offsetWidth / 2);
24008                    cy = y - Math.round(el[i].offsetHeight / 2);
24009
24010                    this.pages[m][n] = {
24011                        x: x,
24012                        y: y,
24013                        width: el[i].offsetWidth,
24014                        height: el[i].offsetHeight,
24015                        cx: cx,
24016                        cy: cy
24017                    };
24018
24019                    if ( x > this.maxScrollX ) {
24020                        m++;
24021                    }
24022                }
24023            }
24024
24025            this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
24026
24027            // Update snap threshold if needed
24028            if ( this.options.snapThreshold % 1 === 0 ) {
24029                this.snapThresholdX = this.options.snapThreshold;
24030                this.snapThresholdY = this.options.snapThreshold;
24031            } else {
24032                this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
24033                this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
24034            }
24035        });
24036
24037        this.on('flick', function () {
24038            var time = this.options.snapSpeed || Math.max(
24039                    Math.max(
24040                        Math.min(Math.abs(this.x - this.startX), 1000),
24041                        Math.min(Math.abs(this.y - this.startY), 1000)
24042                    ), 300);
24043
24044            this.goToPage(
24045                this.currentPage.pageX + this.directionX,
24046                this.currentPage.pageY + this.directionY,
24047                time
24048            );
24049        });
24050    },
24051
24052    _nearestSnap: function (x, y) {
24053        if ( !this.pages.length ) {
24054            return { x: 0, y: 0, pageX: 0, pageY: 0 };
24055        }
24056
24057        var i = 0,
24058            l = this.pages.length,
24059            m = 0;
24060
24061        // Check if we exceeded the snap threshold
24062        if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
24063            Math.abs(y - this.absStartY) < this.snapThresholdY ) {
24064            return this.currentPage;
24065        }
24066
24067        if ( x > 0 ) {
24068            x = 0;
24069        } else if ( x < this.maxScrollX ) {
24070            x = this.maxScrollX;
24071        }
24072
24073        if ( y > 0 ) {
24074            y = 0;
24075        } else if ( y < this.maxScrollY ) {
24076            y = this.maxScrollY;
24077        }
24078
24079        for ( ; i < l; i++ ) {
24080            if ( x >= this.pages[i][0].cx ) {
24081                x = this.pages[i][0].x;
24082                break;
24083            }
24084        }
24085
24086        l = this.pages[i].length;
24087
24088        for ( ; m < l; m++ ) {
24089            if ( y >= this.pages[0][m].cy ) {
24090                y = this.pages[0][m].y;
24091                break;
24092            }
24093        }
24094
24095        if ( i == this.currentPage.pageX ) {
24096            i += this.directionX;
24097
24098            if ( i < 0 ) {
24099                i = 0;
24100            } else if ( i >= this.pages.length ) {
24101                i = this.pages.length - 1;
24102            }
24103
24104            x = this.pages[i][0].x;
24105        }
24106
24107        if ( m == this.currentPage.pageY ) {
24108            m += this.directionY;
24109
24110            if ( m < 0 ) {
24111                m = 0;
24112            } else if ( m >= this.pages[0].length ) {
24113                m = this.pages[0].length - 1;
24114            }
24115
24116            y = this.pages[0][m].y;
24117        }
24118
24119        return {
24120            x: x,
24121            y: y,
24122            pageX: i,
24123            pageY: m
24124        };
24125    },
24126
24127    goToPage: function (x, y, time, easing) {
24128        easing = easing || this.options.bounceEasing;
24129
24130        if ( x >= this.pages.length ) {
24131            x = this.pages.length - 1;
24132        } else if ( x < 0 ) {
24133            x = 0;
24134        }
24135
24136        if ( y >= this.pages[x].length ) {
24137            y = this.pages[x].length - 1;
24138        } else if ( y < 0 ) {
24139            y = 0;
24140        }
24141
24142        var posX = this.pages[x][y].x,
24143            posY = this.pages[x][y].y;
24144
24145        time = time === undefined ? this.options.snapSpeed || Math.max(
24146            Math.max(
24147                Math.min(Math.abs(posX - this.x), 1000),
24148                Math.min(Math.abs(posY - this.y), 1000)
24149            ), 300) : time;
24150
24151        this.currentPage = {
24152            x: posX,
24153            y: posY,
24154            pageX: x,
24155            pageY: y
24156        };
24157
24158        this.scrollTo(posX, posY, time, easing);
24159    },
24160
24161    next: function (time, easing) {
24162        var x = this.currentPage.pageX,
24163            y = this.currentPage.pageY;
24164
24165        x++;
24166
24167        if ( x >= this.pages.length && this.hasVerticalScroll ) {
24168            x = 0;
24169            y++;
24170        }
24171
24172        this.goToPage(x, y, time, easing);
24173    },
24174
24175    prev: function (time, easing) {
24176        var x = this.currentPage.pageX,
24177            y = this.currentPage.pageY;
24178
24179        x--;
24180
24181        if ( x < 0 && this.hasVerticalScroll ) {
24182            x = 0;
24183            y--;
24184        }
24185
24186        this.goToPage(x, y, time, easing);
24187    },
24188
24189    _initKeys: function (e) {
24190        // default key bindings
24191        var keys = {
24192            pageUp: 33,
24193            pageDown: 34,
24194            end: 35,
24195            home: 36,
24196            left: 37,
24197            up: 38,
24198            right: 39,
24199            down: 40
24200        };
24201        var i;
24202
24203        // if you give me characters I give you keycode
24204        if ( typeof this.options.keyBindings == 'object' ) {
24205            for ( i in this.options.keyBindings ) {
24206                if ( typeof this.options.keyBindings[i] == 'string' ) {
24207                    this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
24207deAt(0);
24208                }
24209            }
24210        } else {
24211            this.options.keyBindings = {};
24212        }
24213
24214        for ( i in keys ) {
24215            this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
24216        }
24217
24218        utils.addEvent(window, 'keydown', this);
24219
24220        this.on('destroy', function () {
24221            utils.removeEvent(window, 'keydown', this);
24222        });
24223    },
24224
24225    _key: function (e) {
24226        if ( !this.enabled ) {
24227            return;
24228        }
24229
24230        var snap = this.options.snap,   // we are using this alot, better to cache it
24231            newX = snap ? this.currentPage.pageX : this.x,
24232            newY = snap ? this.currentPage.pageY : this.y,
24233            now = utils.getTime(),
24234            prevTime = this.keyTime || 0,
24235            acceleration = 0.250,
24236            pos;
24237
24238        if ( this.options.useTransition && this.isInTransition ) {
24239            pos = this.getComputedPosition();
24240
24241            this._translate(Math.round(pos.x), Math.round(pos.y));
24242            this.isInTransition = false;
24243        }
24244
24245        this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
24246
24247        switch ( e.keyCode ) {
24248            case this.options.keyBindings.pageUp:
24249                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
24250                    newX += snap ? 1 : this.wrapperWidth;
24251                } else {
24252                    newY += snap ? 1 : this.wrapperHeight;
24253                }
24254                break;
24255            case this.options.keyBindings.pageDown:
24256                if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
24257                    newX -= snap ? 1 : this.wrapperWidth;
24258                } else {
24259                    newY -= snap ? 1 : this.wrapperHeight;
24260                }
24261                break;
24262            case this.options.keyBindings.end:
24263                newX = snap ? this.pages.length-1 : this.maxScrollX;
24264                newY = snap ? this.pages[0].length-1 : this.maxScrollY;
24265                break;
24266            case this.options.keyBindings.home:
24267                newX = 0;
24268                newY = 0;
24269                break;
24270            case this.options.keyBindings.left:
24271                newX += snap ? -1 : 5 + this.keyAcceleration>>0;
24272                break;
24273            case this.options.keyBindings.up:
24274                newY += snap ? 1 : 5 + this.keyAcceleration>>0;
24275                break;
24276            case this.options.keyBindings.right:
24277                newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
24278                break;
24279            case this.options.keyBindings.down:
24280                newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
24281                break;
24282            default:
24283                return;
24284        }
24285
24286        if ( snap ) {
24287            this.goToPage(newX, newY);
24288            return;
24289        }
24290
24291        if ( newX > 0 ) {
24292            newX = 0;
24293            this.keyAcceleration = 0;
24294        } else if ( newX < this.maxScrollX ) {
24295            newX = this.maxScrollX;
24296            this.keyAcceleration = 0;
24297        }
24298
24299        if ( newY > 0 ) {
24300            newY = 0;
24301            this.keyAcceleration = 0;
24302        } else if ( newY < this.maxScrollY ) {
24303            newY = this.maxScrollY;
24304            this.keyAcceleration = 0;
24305        }
24306
24307        this.scrollTo(newX, newY, 0);
24308
24309        this.keyTime = now;
24310    },
24311
24312    _animate: function (destX, destY, duration, easingFn) {
24313        var that = this,
24314            startX = this.x,
24315            startY = this.y,
24316            startTime = utils.getTime(),
24317            destTime = startTime + duration;
24318
24319        function step () {
24320            var now = utils.getTime(),
24321                newX, newY,
24322                easing;
24323
24324            if ( now >= destTime ) {
24325                that.isAnimating = false;
24326                that._translate(destX, destY);
24327
24328                if ( !that.resetPosition(that.options.bounceTime) ) {
24329                    that._execEvent('scrollEnd');
24330                }
24331
24332                return;
24333            }
24334
24335            now = ( now - startTime ) / duration;
24336            easing = easingFn(now);
24337            newX = ( destX - startX ) * easing + startX;
24338            newY = ( destY - startY ) * easing + startY;
24339            that._translate(newX, newY);
24340
24341            if ( that.isAnimating ) {
24342                rAF(step);
24343            }
24344        }
24345
24346        this.isAnimating = true;
24347        step();
24348    },
24349    handleEvent: function (e) {
24350        switch ( e.type ) {
24351            case 'touchstart':
24352            case 'pointerdown':
24353            case 'MSPointerDown':
24354            case 'mousedown':
24355                this._start(e);
24356                break;
24357            case 'touchmove':
24358            case 'pointermove':
24359            case 'MSPointerMove':
24360            case 'mousemove':
24361                this._move(e);
24362                break;
24363            case 'touchend':
24364            case 'pointerup':
24365            case 'MSPointerUp':
24366            case 'mouseup':
24367            case 'touchcancel':
24368            case 'pointercancel':
24369            case 'MSPointerCancel':
24370            case 'mousecancel':
24371                this._end(e);
24372                break;
24373            case 'orientationchange':
24374            case 'resize':
24375                this._resize();
24376                break;
24377            case 'transitionend':
24378            case 'webkitTransitionEnd':
24379            case 'oTransitionEnd':
24380            case 'MSTransitionEnd':
24381                this._transitionEnd(e);
24382                break;
24383            case 'wheel':
24384            case 'DOMMouseScroll':
24385            case 'mousewheel':
24386                this._wheel(e);
24387                break;
24388            case 'keydown':
24389                this._key(e);
24390                break;
24391            case 'click':
24392                if ( this.enabled && !e._constructed ) {
24393                    e.preventDefault();
24394                    e.stopPropagation();
24395                }
24396                break;
24397        }
24398    }
24399};
24400function createDefaultScrollbar (direction, interactive, type) {
24401    var scrollbar = document.createElement('div'),
24402        indicator = document.createElement('div');
24403
24404    if ( type === true ) {
24405        scrollbar.style.cssText = 'position:absolute;z-index:9999';
24406        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';
24407    }
24408
24409    indicator.className = 'iScrollIndicator';
24410
24411    if ( direction == 'h' ) {
24412        if ( type === true ) {
24413            scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
24414            indicator.style.height = '100%';
24415        }
24416        scrollbar.className = 'iScrollHorizontalScrollbar';
24417    } else {
24418        if ( type === true ) {
24419            scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
24420            indicator.style.width = '100%';
24421        }
24422        scrollbar.className = 'iScrollVerticalScrollbar';
24423    }
24424
24425    scrollbar.style.cssText += ';overflow:hidden';
24426
24427    if ( !interactive ) {
24428        scrollbar.style.pointerEvents = 'none';
24429    }
24430
24431    scrollbar.appendChild(indicator);
24432
24433    return scrollbar;
24434}
24435
24436function Indicator (scroller, options) {
24437    this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
24438    this.wrapperStyle = this.wrapper.style;
24439    this.indicator = this.wrapper.children[0];
24440    this.indicatorStyle = this.indicator.style;
24441    this.scroller = scroller;
24442
24443    this.options = {
24444        listenX: true,
24445        listenY: true,
24446        interactive: false,
24447        resize: true,
24448        defaultScrollbars: false,
24449        shrink: false,
24450        fade: false,
24451        speedRatioX: 0,
24452        speedRatioY: 0
24453    };
24454
24455    for ( var i in options ) {
24456        this.options[i] = options[i];
24457    }
24458
24459    this.sizeRatioX = 1;
24460    this.sizeRatioY = 1;
24461    this.maxPosX = 0;
24462    this.maxPosY = 0;
24463
24464    if ( this.options.interactive ) {
24465        if ( !this.options.disableTouch ) {
24466            utils.addEvent(this.indicator, 'touchstart', this);
24467            utils.addEvent(window, 'touchend', this);
24468        }
24469        if ( !this.options.disablePointer ) {
24470            utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
24471            utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
24472        }
24473        if ( !this.options.disableMouse ) {
24474            utils.addEvent(this.indicator, 'mousedown', this);
24475            utils.addEvent(window, 'mouseup', this);
24476        }
24477    }
24478
24479    if ( this.options.fade ) {
24480        this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
24481        var durationProp = utils.style.transitionDuration;
24482        if(!durationProp) {
24483            return;
24484        }
24485        this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
24486        // remove 0.0001ms
24487        var self = this;
24488        if(utils.isBadAndroid) {
24489            rAF(function() {
24490                if(self.wrapperStyle[durationProp] === '0.0001ms') {
24491                    self.wrapperStyle[durationProp] = '0s';
24492                }
24493            });
24494        }
24495        this.wrapperStyle.opacity = '0';
24496    }
24497}
24498
24499Indicator.prototype = {
24500    handleEvent: function (e) {
24501        switch ( e.type ) {
24502            case 'touchstart':
24503            case 'pointerdown':
24504            case 'MSPointerDown':
24505            case 'mousedown':
24506                this._start(e);
24507                break;
24508            case 'touchmove':
24509            case 'pointermove':
24510            case 'MSPointerMove':
24511            case 'mousemove':
24512                this._move(e);
24513                break;
24514            case 'touchend':
24515            case 'pointerup':
24516            case 'MSPointerUp':
24517            case 'mouseup':
24518            case 'touchcancel':
24519            case 'pointercancel':
24520            case 'MSPointerCancel':
24521            case 'mousecancel':
24522                this._end(e);
24523                break;
24524        }
24525    },
24526
24527    destroy: function () {
24528        if ( this.options.fadeScrollbars ) {
24529            clearTimeout(this.fadeTimeout);
24530            this.fadeTimeout = null;
24531        }
24532        if ( this.options.interactive ) {
24533            utils.removeEvent(this.indicator, 'touchstart', this);
24534            utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
24535            utils.removeEvent(this.indicator, 'mousedown', this);
24536
24537            utils.removeEvent(window, 'touchmove', this);
24538            utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
24539            utils.removeEvent(window, 'mousemove', this);
24540
24541            utils.removeEvent(window, 'touchend', this);
24542            utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
24543            utils.removeEvent(window, 'mouseup', this);
24544        }
24545
24546        if ( this.options.defaultScrollbars ) {
24547            this.wrapper.parentNode.removeChild(this.wrapper);
24548        }
24549    },
24550
24551    _start: function (e) {
24552        var point = e.touches ? e.touches[0] : e;
24553
24554        e.preventDefault();
24555        e.stopPropagation();
24556
24557        this.transitionTime();
24558
24559        this.initiated = true;
24560        this.moved = false;
24561        this.lastPointX = point.pageX;
24562        this.lastPointY = point.pageY;
24563
24564        this.startTime  = utils.getTime();
24565
24566        if ( !this.options.disableTouch ) {
24567            utils.addEvent(window, 'touchmove', this);
24568        }
24569        if ( !this.options.disablePointer ) {
24570            utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
24571        }
24572        if ( !this.options.disableMouse ) {
24573            utils.addEvent(window, 'mousemove', this);
24574        }
24575
24576        this.scroller._execEvent('beforeScrollStart');
24577    },
24578
24579    _move: function (e) {
24580        var point = e.touches ? e.touches[0] : e,
24581            deltaX, deltaY,
24582            newX, newY,
24583            timestamp = utils.getTime();
24584
24585        if ( !this.moved ) {
24586            this.scroller._execEvent('scrollStart');
24587        }
24588
24589        this.moved = true;
24590
24591        deltaX = point.pageX - this.lastPointX;
24592        this.lastPointX = point.pageX;
24593
24594        deltaY = point.pageY - this.lastPointY;
24595        this.lastPointY = point.pageY;
24596
24597        newX = this.x + deltaX;
24598        newY = this.y + deltaY;
24599
24600        this._pos(newX, newY);
24601
24602// INSERT POINT: indicator._move
24603
24604        e.preventDefault();
24605        e.stopPropagation();
24606    },
24607
24608    _end: function (e) {
24609        if ( !this.initiated ) {
24610            return;
24611        }
24612
24613        this.initiated = false;
24614
24615        e.preventDefault();
24616        e.stopPropagation();
24617
24618        utils.removeEvent(window, 'touchmove', this);
24619        utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
24620        utils.removeEvent(window, 'mousemove', this);
24621
24622        if ( this.scroller.options.snap ) {
24623            var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
24624
24625            var time = this.options.snapSpeed || Math.max(
24626                    Math.max(
24627                        Math.min(Math.abs(this.scroller.x - snap.x), 1000),
24628                        Math.min(Math.abs(this.scroller.y - snap.y), 1000)
24629                    ), 300);
24630
24631            if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
24632                this.scroller.directionX = 0;
24633                this.scroller.directionY = 0;
24634                this.scroller.currentPage = snap;
24635                this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
24636            }
24637        }
24638
24639        if ( this.moved ) {
24640            this.scroller._execEvent('scrollEnd');
24641        }
24642    },
24643
24644    transitionTime: function (time) {
24645        time = time || 0;
24646        var durationProp = utils.style.transitionDuration;
24647        if(!durationProp) {
24648            return;
24649        }
24650
24651        this.indicatorStyle[durationProp] = time + 'ms';
24652
24653        if ( !time && utils.isBadAndroid ) {
24654            this.indicatorStyle[durationProp] = '0.0001ms';
24655            // remove 0.0001ms
24656            var self = this;
24657            rAF(function() {
24658                if(self.indicatorStyle[durationProp] === '0.0001ms') {
24659                    self.indicatorStyle[durationProp] = '0s';
24660                }
24661            });
24662        }
24663    },
24664
24665    transitionTimingFunction: function (easing) {
24666        this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
24667    },
24668
24669    refresh: function () {
24670        this.transitionTime();
24671
24672        if ( this.options.listenX && !this.options.listenY ) {
24673            this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
24674        } else if ( this.options.listenY && !this.options.listenX ) {
24675            this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
24676        } else {
24677            this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
24678        }
24679
24680        if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
24681            utils.addClass(this.wrapper, 'iScrollBothScrollbars');
24682            utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
24683
24684            if ( this.options.defaultScrollbars && this.options.customStyle ) {
24685                if ( this.options.listenX ) {
24686                    this.wrapper.style.right = '8px';
24687                } else {
24688                    this.wrapper.style.bottom = '8px';
24689                }
24690            }
24691        } else {
24692            utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
24693            utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
24694
24695            if ( this.options.defaultScrollbars && this.options.customStyle ) {
24696                if ( this.options.listenX ) {
24697                    this.wrapper.style.right = '2px';
24698                } else {
24699                    this.wrapper.style.bottom = '2px';
24700                }
24701            }
24702        }
24703
24704        var r = this.wrapper.offsetHeight;  // force refresh
24705
24706        if ( this.options.listenX ) {
24707            this.wrapperWidth = this.wrapper.clientWidth;
24708            if ( this.options.resize ) {
24709                this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
24710                this.indicatorStyle.width = this.indicatorWidth + 'px';
24711            } else {
24712                this.indicatorWidth = this.indicator.clientWidth;
24713            }
24714
24715            this.maxPosX = this.wrapperWidth - this.indicatorWidth;
24716
24717            if ( this.options.shrink == 'clip' ) {
24718                this.minBoundaryX = -this.indicatorWidth + 8;
24719                this.maxBoundaryX = this.wrapperWidth - 8;
24720            } else {
24721                this.minBoundaryX = 0;
24722                this.maxBoundaryX = this.maxPosX;
24723            }
24724
24725            this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
24726        }
24727
24728        if ( this.options.listenY ) {
24729            this.wrapperHeight = this.wrapper.clientHeight;
24730            if ( this.options.resize ) {
24731                this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
24732                this.indicatorStyle.height = this.indicatorHeight + 'px';
24733            } else {
24734                this.indicatorHeight = this.indicator.clientHeight;
24735            }
24736
24737            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
24738
24739            if ( this.options.shrink == 'clip' ) {
24740                this.minBoundaryY = -this.indicatorHeight + 8;
24741                this.maxBoundaryY = this.wrapperHeight - 8;
24742            } else {
24743                this.minBoundaryY = 0;
24744                this.maxBoundaryY = this.maxPosY;
24745            }
24746
24747            this.maxPosY = this.wrapperHeight - this.indicatorHeight;
24748            this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
24749        }
24750
24751        this.updatePosition();
24752    },
24753
24754    updatePosition: function () {
24755        var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
24756            y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
24757
24758        if ( !this.options.ignoreBoundaries ) {
24759            if ( x < this.minBoundaryX ) {
24760                if ( this.options.shrink == 'scale' ) {
24761                    this.width = Math.max(this.indicatorWidth + x, 8);
24762                    this.indicatorStyle.width = this.width + 'px';
24763                }
24764                x = this.minBoundaryX;
24765            } else if ( x > this.maxBoundaryX ) {
24766                if ( this.options.shrink == 'scale' ) {
24767                    this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
24768                    this.indicatorStyle.width = this.width + 'px';
24769                    x = this.maxPosX + this.indicatorWidth - this.width;
24770                } else {
24771                    x = this.maxBoundaryX;
24772                }
24773            } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
24774                this.width = this.indicatorWidth;
24775                this.indicatorStyle.width = this.width + 'px';
24776            }
24777
24778            if ( y < this.minBoundaryY ) {
24779                if ( this.options.shrink == 'scale' ) {
24780                    this.height = Math.max(this.indicatorHeight + y * 3, 8);
24781                    this.indicatorStyle.height = this.height + 'px';
24782                }
24783                y = this.minBoundaryY;
24784            } else if ( y > this.maxBoundaryY ) {
24785                if ( this.options.shrink == 'scale' ) {
24786                    this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
24787                    this.indicatorStyle.height = this.height + 'px';
24788                    y = this.maxPosY + this.indicatorHeight - this.height;
24789                } else {
24790                    y = this.maxBoundaryY;
24791                }
24792            } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
24793                this.height = this.indicatorHeight;
24794                this.indicatorStyle.height = this.height + 'px';
24795            }
24796        }
24797
24798        this.x = x;
24799        this.y = y;
24800
24801        if ( this.scroller.options.useTransform ) {
24802            this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
24803        } else {
24804            this.indicatorStyle.left = x + 'px';
24805            this.indicatorStyle.top = y + 'px';
24806        }
24807    },
24808
24809    _pos: function (x, y) {
24810        if ( x < 0 ) {
24811            x = 0;
24812        } else if ( x > this.maxPosX ) {
24813            x = this.maxPosX;
24814        }
24815
24816        if ( y < 0 ) {
24817            y = 0;
24818        } else if ( y > this.maxPosY ) {
24819            y = this.maxPosY;
24820        }
24821
24822        x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
24823        y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
24824
24825        this.scroller.scrollTo(x, y);
24826    },
24827
24828    fade: function (val, hold) {
24829        if ( hold && !this.visible ) {
24830            return;
24831        }
24832
24833        clearTimeout(this.fadeTimeout);
24834        this.fadeTimeout = null;
24835
24836        var time = val ? 250 : 500,
24837            delay = val ? 0 : 300;
24838
24839        val = val ? '1' : '0';
24840
24841        this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
24842
24843        this.fadeTimeout = setTimeout((function (val) {
24844            this.wrapperStyle.opacity = val;
24845            this.visible = +val;
24846        }).bind(this, val), delay);
24847    }
24848};
24849
24850IScroll.utils = utils;
24851
24852if ( typeof module != 'undefined' && module.exports ) {
24853    module.exports = IScroll;
24854} else if ( typeof define == 'function' && define.amd ) {
24855        define( function () { return IScroll; } );
24856} else {
24857    window.IScroll = IScroll;
24858}
24859
24860})(window, document, Math);
24861/*!
24862 * fullPage 2.9.4
24863 * https://github.com/alvarotrigo/fullPage.js
24864 * @license MIT licensed
24865 *
24866 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
24867 */
24868(function(global, factory) {
24869    'use strict';
24870    if (typeof define === 'function' && define.amd) {
24871        define(['jquery'], function($) {
24872          return factory($, global, global.document, global.Math);
24873        });
24874    } else if (typeof exports === "object" && exports) {
24875        module.exports = factory(require('jquery'), global, global.document, global.Math);
24876    } else {
24877        factory(jQuery, global, global.document, global.Math);
24878    }
24879})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
24880    'use strict';
24881
24882    // keeping central set of classnames and selectors
24883    var WRAPPER =               'fullpage-wrapper';
24884    var WRAPPER_SEL =           '.' + WRAPPER;
24885
24886    // slimscroll
24887    var SCROLLABLE =            'fp-scrollable';
24888    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
24889
24890    // util
24891    var RESPONSIVE =            'fp-responsive';
24892    var NO_TRANSITION =         'fp-notransition';
24893    var DESTROYED =             'fp-destroyed';
24894    var ENABLED =               'fp-enabled';
24895    var VIEWING_PREFIX =        'fp-viewing';
24896    var ACTIVE =                'active';
24897    var ACTIVE_SEL =            '.' + ACTIVE;
24898    var COMPLETELY =            'fp-completely';
24899    var COMPLETELY_SEL =        '.' + COMPLETELY;
24900
24901    // section
24902    var SECTION_DEFAULT_SEL =   '.section';
24903    var SECTION =               'fp-section';
24904    var SECTION_SEL =           '.' + SECTION;
24905    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
24906    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
24907    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
24908    var TABLE_CELL =            'fp-tableCell';
24909    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
24910    var AUTO_HEIGHT =           'fp-auto-height';
24911    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
24912    var NORMAL_SCROLL =         'fp-normal-scroll';
24913    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
24914
24915    // section nav
24916    var SECTION_NAV =           'fp-nav';
24917    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
24918    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
24919    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
24920    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
24921
24922    // slide
24923    var SLIDE_DEFAULT_SEL =     '.slide';
24924    var SLIDE =                 'fp-slide';
24925    var SLIDE_SEL =             '.' + SLIDE;
24926    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
24927    var SLIDES_WRAPPER =        'fp-slides';
24928    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
24929    var SLIDES_CONTAINER =      'fp-slidesContainer';
24930    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
24931    var TABLE =                 'fp-table';
24932
24933    // slide nav
24934    var SLIDES_NAV =            'fp-slidesNav';
24935    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
24936    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
24937    var SLIDES_ARROW =          'fp-controlArrow';
24938    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
24939    var SLIDES_PREV =           'fp-prev';
24940    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
24941    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
24942    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
24943    var SLIDES_NEXT =           'fp-next';
24944    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
24945    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
24946    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
24947
24948    var $window = $(window);
24949    var $document = $(document);
24950
24951    // Default options for iScroll.js used when using scrollOverflow
24952    var iscrollOptions = {
24953        scrollbars: true,
24954        mouseWheel: true,
24955        hideScrollbars: false,
24956        fadeScrollbars: false,
24957        disableMouse: true,
24958        interactiveScrollbars: true,
24959        bounce: false,
24960    };
24961
24962    $.fn.fullpage = function(options) {
24963        //only once my friend!
24964        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
24965
24966        // common jQuery objects
24967        var $htmlBody = $('html, body');
24968        var $body = $('body');
24969
24970        var FP = $.fn.fullpage;
24971
24972        // Creating some defaults, extending them with any options that were provided
24973        options = $.extend({
24974            //navigation
24975            menu: false,
24976            anchors:[],
24977            lockAnchors: false,
24978            navigation: false,
24979            navigationPosition: 'right',
24980            navigationTooltips: [],
24981            showActiveTooltip: false,
24982            slidesNavigation: false,
24983            slidesNavPosition: 'bottom',
24984            scrollBar: false,
24985            hybrid: false,
24986
24987            //scrolling
24988            css3: true,
24989            scrollingSpeed: 700,
24990            autoScrolling: true,
24991            fitToSection: true,
24992            fitToSectionDelay: 1000,
24993            easing: 'easeInOutCubic',
24994            easingcss3: 'ease',
24995            loopBottom: false,
24996            loopTop: false,
24997            loopHorizontal: true,
24998            continuousVertical: false,
24999            continuousHorizontal: false,
25000            scrollHorizontally: false,
25001            interlockedSlides: false,
25002            dragAndMove: false,
25003            offsetSections: false,
25004            resetSliders: false,
25005            fadingEffect: false,
25006            normalScrollElements: null,
25007            scrollOverflow: false,
25008            scrollOverflowReset: false,
25009            scrollOverflowHandler: iscrollHandler,
25010            scrollOverflowOptions: null,
25011            touchSensitivity: 5,
25012            normalScrollElementTouchThreshold: 5,
25013            bigSectionsDestination: null,
25014
25015            //Accessibility
25016            keyboardScrolling: true,
25017            animateAnchor: true,
25018            recordHistory: true,
25019
25020            //design
25021            controlArrows: true,
25022            controlArrowColor: '#fff',
25023            verticalCentered: true,
25024            sectionsColor : [],
25025            paddingTop: 0,
25026            paddingBottom: 0,
25027            fixedElements: null,
25028            responsive: 0, //backwards compabitility with responsiveWiddth
25029            responsiveWidth: 0,
25030            responsiveHeight: 0,
25031            responsiveSlides: false,
25032            parallax: false,
25033            parallaxOptions: {
25034                type: 'reveal',
25035                percentage: 62,
25036                property: 'translate'
25037            },
25038
25039            //Custom selectors
25040            sectionSelector: SECTION_DEFAULT_SEL,
25041            slideSelector: SLIDE_DEFAULT_SEL,
25042
25043            //events
25044            afterLoad: null,
25045            onLeave: null,
25046            afterRender: null,
25047            afterResize: null,
25048            afterReBuild: null,
25049            afterSlideLoad: null,
25050            onSlideLeave: null,
25051            afterResponsive: null,
25052
25053            lazyLoading: true
25054        }, options);
25055
25056        //flag to avoid very fast sliding for landscape sliders
25057        var slideMoving = false;
25058
25059        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
25060        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
25061        var container = $(this);
25062        var windowsHeight = $window.height();
25063        var isResizing = false;
25064        var isWindowFocused = true;
25065        var lastScrolledDestiny;
25066        var lastScrolledSlide;
25067        var canScroll = true;
25068        var scrollings = [];
25069        var controlPressed;
25070        var startingSection;
25071        var isScrollAllowed = {};
25072        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
25073        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
25074        var MSPointer = getMSPointer();
25075        var events = {
25076            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
25077            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
25078        };
25079
25080        //cheks for passive event support
25081        //added by Uncode from new fullPage updates
25082        var g_supportsPassive = false;
25083        try {
25084          var opts = Object.defineProperty({}, 'passive', {
25085            get: function() {
25086              g_supportsPassive = true;
25087            }
25088          });
25089          window.addEventListener("testPassive", null, opts);
25090          window.removeEventListener("testPassive", null, opts);
25091        } catch (e) {}
25092
25093        //timeouts
25094        var resizeId;
25095        var afterSectionLoadsId;
25096        var afterSlideLoadsId;
25097        var scrollId;
25098        var scrollId2;
25099        var keydownId;
25100        var originals = $.extend(true, {}, options); //deep copy
25101
25102        //Uncode addition
25103        var $masthead = $('#masthead');
25104        var hideMenu = !$('body').hasClass('vmenu') && $('body').hasClass('uncode-fp-menu-hide') ? true : false;
25105        var menuHeight = $masthead.hasClass('menu-transparent') || hideMenu ? 0 : UNCODE.menuHeight;
25106        var bodyBorder = UNCODE.bodyBorder;
25107        var adminBarHeight = UNCODE.adminBarHeight;
25108
25109        displayWarnings();
25110
25111        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
25112        iscrollOptions.click = isTouch; // see #2035
25113
25114        //extending iScroll options with the user custom ones
25115        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
25116
25117        //easeInOutCubic animation included in the plugin
25118        $.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;}});
25119
25120        /**
25121        * Sets the autoScroll option.
25122        * It changes the scroll bar visibility and the history of the site as a result.
25123        */
25124        function setAutoScrolling(value, type){
25125            //removing the transformation
25126            if(!value){
25127                silentScroll(0);
25128            }
25129
25130            setVariableState('autoScrolling', value, type);
25131
25132            var element = $(SECTION_ACTIVE_SEL);
25133
25134            if(options.autoScrolling && !options.scrollBar){
25135                $htmlBody.css({
25136                    'overflow' : 'hidden !important',
25137                    'height' : '100%'
25138                });
25139
25140                //Uncode addition
25141                //setRecordHistory(originals.recordHistory, 'internal');
25142
25143                //for IE touch devices
25144                container.css({
25145                    '-ms-touch-action': 'none',
25146                    'touch-action': 'none'
25147                });
25148
25149                if(element.length){
25150                    //moving the container up
25151                    silentScroll(element.position().top);
25152                }
25153
25154            }else{
25155                $htmlBody.css({
25156                    'overflow' : 'visible !important',
25157                    'height' : 'initial'
25158                });
25159
25160                //Uncode addition
25161                //setRecordHistory(false, 'internal');
25162
25163                //for IE touch devices
25164                container.css({
25165                    '-ms-touch-action': '',
25166                    'touch-action': ''
25167                });
25168
25169                //scrolling the page to the section with no animation
25170                if (element.length) {
25171                    $htmlBody.scrollTop(element.position().top);
25172                }
25173            }
25174        }
25175
25176        /**
25177        * Defines wheter to record the history for each hash change in the URL.
25178        */
25179        function setRecordHistory(value, type){
25180            setVariableState('recordHistory', value, type);
25181        }
25182
25183        /**
25184        * Defines the scrolling speed
25185        */
25186        function setScrollingSpeed(value, type){
25187            setVariableState('scrollingSpeed', value, type);
25188        }
25189
25190        /**
25191        * Sets fitToSection
25192        */
25193        function setFitToSection(value, type){
25194            setVariableState('fitToSection', value, type);
25195        }
25196
25197        /**
25198        * Sets lockAnchors
25199        */
25200        function setLockAnchors(value){
25201            options.lockAnchors = value;
25202        }
25203
25204        /**
25205        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
25206        */
25207        function setMouseWheelScrolling(value){
25208            if(value){
25209                addMouseWheelHandler();
25210                addMiddleWheelHandler();
25211            }else{
25212                removeMouseWheelHandler();
25213                removeMiddleWheelHandler();
25214            }
25215        }
25216
25217        /**
25218        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
25219        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
25220        *
25221        * @param directions string containing the direction or directions separated by comma.
25222        */
25223        function setAllowScrolling(value, directions){
25224            if(typeof directions !== 'undefined'){
25225                directions = directions.replace(/ /g,'').split(',');
25226
25227                $.each(directions, function (index, direction){
25228                    setIsScrollAllowed(value, direction, 'm');
25229                });
25230            }
25231            else if(value){
25232                setMouseWheelScrolling(true);
25233                addTouchHandler();
25234            }else{
25235                setMouseWheelScrolling(false);
25236                removeTouchHandler();
25237            }
25238        }
25239
25240        /**
25241        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
25242        */
25243        function setKeyboardScrolling(value, directions){
25244            if(typeof directions !== 'undefined'){
25245                directions = directions.replace(/ /g,'').split(',');
25246
25247                $.each(directions, function (index, direction){
25248                    setIsScrollAllowed(value, direction, 'k');
25249                });
25250            }else{
25251                options.keyboardScrolling = value;
25252            }
25253        }
25254
25255        /**
25256        * Moves the page up one section.
25257        */
25258        function moveSectionUp(){
25259            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
25260
25261            //looping to the bottom if there's no more sections above
25262            if (!prev.length && (options.loopTop || options.continuousVertical)) {
25263                prev = $(SECTION_SEL).last();
25264            }
25265
25266            if (prev.length) {
25267                scrollPage(prev, null, true);
25268            }
25269        }
25270
25271        /**
25272        * Moves the page down one section.
25273        */
25274        function moveSectionDown(){
25275            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
25276
25277            //looping to the top if there's no more sections below
25278            if(!next.length &&
25279                (options.loopBottom || options.continuousVertical)){
25280                next = $(SECTION_SEL).first();
25281            }
25282
25283            if(next.length){
25284                scrollPage(next, null, false);
25285            }
25286        }
25287
25288        /**
25289        * Moves the page to the given section and slide with no animation.
25290        * Anchors or index positions can be used as params.
25291        */
25292        function silentMoveTo(sectionAnchor, slideAnchor){
25293            setScrollingSpeed (0, 'internal');
25294            moveTo(sectionAnchor, slideAnchor);
25295            setScrollingSpeed (originals.scrollingSpeed, 'internal');
25296        }
25297
25298        /**
25299        * Moves the page to the given section and slide.
25300        * Anchors or index positions can be used as params.
25301        */
25302        function moveTo(sectionAnchor, slideAnchor){
25303            var destiny = getSectionByAnchor(sectionAnchor);
25304
25305            if (typeof slideAnchor !== 'undefined'){
25306                scrollPageAndSlide(sectionAnchor, slideAnchor);
25307            }else if(destiny.length > 0){
25308                scrollPage(destiny);
25309            }
25310        }
25311
25312        /**
25313        * Slides right the slider of the active section.
25314        * Optional `section` param.
25315        */
25316        function moveSlideRight(section){
25317            moveSlide('right', section);
25318        }
25319
25320        /**
25321        * Slides left the slider of the active section.
25322        * Optional `section` param.
25323        */
25324        function moveSlideLeft(section){
25325            moveSlide('left', section);
25326        }
25327
25328        /**
25329         * When resizing is finished, we adjust the slides sizes and positions
25330         */
25331        function reBuild(resizing){
25332            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
25333
25334            isResizing = true;
25335
25336            windowsHeight = $window.height();  //updating global var
25337
25338            $(SECTION_SEL).each(function(){
25339                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
25340                var slides = $(this).find(SLIDE_SEL);
25341
25342                //adjusting the height of the table-cell for IE and Firefox
25343                if(options.verticalCentered){
25344                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
25345                }
25346
25347                $(this).css('height', windowsHeight + 'px');
25348
25349                //resizing the scrolling divs
25350                if(options.scrollOverflow){
25351                    if(slides.length){
25352                        slides.each(function(){
25353                            createScrollBar($(this));
25354                        });
25355                    }else{
25356                        createScrollBar($(this));
25357                    }
25358                }
25359
25360                //adjusting the position fo the FULL WIDTH slides...
25361                if (slides.length > 1) {
25362                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
25363                }
25364            });
25365
25366            var activeSection = $(SECTION_ACTIVE_SEL);
25367            var sectionIndex = activeSection.index(SECTION_SEL);
25368
25369            //isn't it the first section?
25370            if(sectionIndex){
25371                //adjusting the position for the current section
25372                silentMoveTo(sectionIndex + 1);
25373            }
25374
25375            isResizing = false;
25376            // Uncode change
25377            // $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
25378            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container, getTableHeight());
25379            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
25380        }
25381
25382        /**
25383        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
25384        * are smaller than the set limit values.
25385        */
25386        function setResponsive(active){
25387            var isResponsive = $body.hasClass(RESPONSIVE);
25388
25389            if(active){
25390                if(!isResponsive){
25391                    setAutoScrolling(false, 'internal');
25392                    setFitToSection(false, 'internal');
25393                    $(SECTION_NAV_SEL).hide();
25394                    $body.addClass(RESPONSIVE);
25395                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
25396                }
25397            }
25398            else if(isResponsive){
25399                setAutoScrolling(originals.autoScrolling, 'internal');
25400                setFitToSection(originals.autoScrolling, 'internal');
25401                $(SECTION_NAV_SEL).show();
25402                $body.removeClass(RESPONSIVE);
25403                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
25404            }
25405        }
25406
25407        if($(this).length){
25408            //public functions
25409            FP.setAutoScrolling = setAutoScrolling;
25410            FP.setRecordHistory = setRecordHistory;
25411            FP.setScrollingSpeed = setScrollingSpeed;
25412            FP.setFitToSection = setFitToSection;
25413            FP.setLockAnchors = setLockAnchors;
25414            FP.setMouseWheelScrolling = setMouseWheelScrolling;
25415            FP.setAllowScrolling = setAllowScrolling;
25416            FP.setKeyboardScrolling = setKeyboardScrolling;
25417            FP.moveSectionUp = moveSectionUp;
25418            FP.moveSectionDown = moveSectionDown;
25419            FP.silentMoveTo = silentMoveTo;
25420            FP.moveTo = moveTo;
25421            FP.moveSlideRight = moveSlideRight;
25422            FP.moveSlideLeft = moveSlideLeft;
25423            FP.fitToSection = fitToSection;
25424            FP.reBuild = reBuild;
25425            FP.setResponsive = setResponsive;
25426            FP.destroy = destroy;
25427
25428            init();
25429
25430            bindEvents();
25431        }
25432
25433        function init(){
25434            //if css3 is not supported, it will use jQuery animations
25435            if(options.css3){
25436                options.css3 = support3d();
25437            }
25438
25439            options.scrollBar = options.scrollBar || options.hybrid;
25440
25441            setOptionsFromDOM();
25442            prepareDom();
25443            setAllowScrolling(true);
25444            setAutoScrolling(options.autoScrolling, 'internal');
25445            responsive();
25446
25447            //setting the class for the body element
25448            setBodyClass();
25449
25450            //Uncode addition
25451            // if(document.readyState === 'complete'){
25452            //     scrollToAnchor();
25453            // }
25454            // $window.on('load', scrollToAnchor);
25455        }
25456
25457        function bindEvents(){
25458            $window
25459                //when scrolling...
25460                //.on('scroll', scrollHandler)
25461
25462                //detecting any change on the URL to scroll to the given anchor link
25463                //(a way to detect back history button as we play with the hashes on the URL)
25464                .on('hashchange', hashChangeHandler)
25465
25466                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
25467                .blur(blurHandler)
25468
25469                //when resizing the site, we adjust the heights of the sections, slimScroll...
25470                .resize(resizeHandler);
25471
25472            $document
25473                //Sliding with arrow keys, both, vertical and horizontal
25474                .keydown(keydownHandler)
25475
25476                //to prevent scrolling while zooming
25477                .keyup(keyUpHandler)
25478
25479                //Scrolls to the section when clicking the navigation bullet
25480                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
25481
25482                //Scrolls the slider to the given slide destination for the given section
25483                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
25484
25485                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
25486
25487            //Scrolling horizontally when clicking on the slider controls.
25488            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
25489
25490            /**
25491            * Applying normalScroll elements.
25492            * Ignoring the scrolls over the specified selectors.
25493            */
25494            if(options.normalScrollElements){
25495                $document.on('mouseenter', options.normalScrollElements, function () {
25496                    setMouseWheelScrolling(false);
25497                });
25498
25499                $document.on('mouseleave', options.normalScrollElements, function(){
25500                    setMouseWheelScrolling(true);
25501                });
25502            }
25503        }
25504
25505        /**
25506        * Setting options from DOM elements if they are not provided.
25507        */
25508        function setOptionsFromDOM(){
25509            var sections = container.find(options.sectionSelector);
25510
25511            //no anchors option? Checking for them in the DOM attributes
25512            if(!options.anchors.length){
25513                options.anchors = sections.filter('[data-anchor]').map(function(){
25514                    return $(this).data('anchor').toString();
25515                }).get();
25516            }
25517
25518            //no tooltips option? Checking for them in the DOM attributes
25519            if(!options.navigationTooltips.length){
25520                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
25521                    return $(this).data('tooltip').toString();
25522                }).get();
25523            }
25524        }
25525
25526        /**
25527        * Works over the DOM structure to set it up for the current fullpage options.
25528        */
25529        function prepareDom(){
25530            container.css({
25531                'height': '100%',
25532                'position': 'relative'
25533            });
25534
25535            //adding a class to recognize the container internally in the code
25536            container.addClass(WRAPPER);
25537            $('html').addClass(ENABLED);
25538
25539            windowsHeight = $window.height();
25540
25541            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
25542
25543            addInternalSelectors();
25544
25545             //styling the sections / slides / menu
25546            $(SECTION_SEL).each(function(index){
25547                var section = $(this);
25548                var slides = section.find(SLIDE_SEL);
25549                var numSlides = slides.length;
25550
25551                styleSection(section, index);
25552                styleMenu(section, index);
25553
25554                // if there's any slide
25555                if (numSlides > 0) {
25556                    styleSlides(section, slides, numSlides);
25557                }else{
25558                    if(options.verticalCentered){
25559                        addTableClass(section);
25560                    }
25561                }
25562            });
25563
25564            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
25565            if(options.fixedElements && options.css3){
25566                $(options.fixedElements).appendTo($body);
25567            }
25568
25569            //vertical centered of the navigation + active bullet
25570            if(options.navigation){
25571                addVerticalNavigation();
25572            }
25573
25574            enableYoutubeAPI();
25575
25576            if(options.scrollOverflow){
25577                if(document.readyState === 'complete'){
25578                    createScrollBarHandler();
25579                }
25580                //after DOM and images are loaded
25581                $window.on('load', createScrollBarHandler);
25582            }else{
25583                afterRenderActions();
25584            }
25585        }
25586
25587        /**
25588        * Styles the horizontal slides for a section.
25589        */
25590        function styleSlides(section, slides, numSlides){
25591            var sliderWidth = numSlides * 100;
25592            var slideWidth = 100 / numSlides;
25593
25594            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
25595            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
25596
25597            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
25598
25599            if(numSlides > 1){
25600                if(options.controlArrows){
25601                    createSlideArrows(section);
25602                }
25603
25604                if(options.slidesNavigation){
25605                    addSlidesNavigation(section, numSlides);
25606                }
25607            }
25608
25609            slides.each(function(index) {
25610                $(this).css('width', slideWidth + '%');
25611
25612                if(options.verticalCentered){
25613                    addTableClass($(this));
25614                }
25615            });
25616
25617            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
25618
25619            //if the slide won't be an starting point, the default will be the first one
25620            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
25620ide by default.
25621            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
25622                silentLandscapeScroll(startingSlide, 'internal');
25623            }else{
25624                slides.eq(0).addClass(ACTIVE);
25625            }
25626        }
25627
25628        /**
25629        * Styling vertical sections
25630        */
25631        function styleSection(section, index){
25632            //if no active section is defined, the 1st one will be the default one
25633            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
25634                section.addClass(ACTIVE);
25635            }
25636            startingSection = $(SECTION_ACTIVE_SEL);
25637
25638            section.css('height', windowsHeight + 'px');
25639
25640            if(options.paddingTop){
25641                section.css('padding-top', options.paddingTop);
25642            }
25643
25644            if(options.paddingBottom){
25645                section.css('padding-bottom', options.paddingBottom);
25646            }
25647
25648            if (typeof options.sectionsColor[index] !==  'undefined') {
25649                section.css('background-color', options.sectionsColor[index]);
25650            }
25651
25652            if (typeof options.anchors[index] !== 'undefined') {
25653                section.attr('data-anchor', options.anchors[index]);
25654            }
25655        }
25656
25657        /**
25658        * Sets the data-anchor attributes to the menu elements and activates the current one.
25659        */
25660        function styleMenu(section, index){
25661            if (typeof options.anchors[index] !== 'undefined') {
25662                //activating the menu / nav element on load
25663                if(section.hasClass(ACTIVE)){
25664                    activateMenuAndNav(options.anchors[index], index);
25665                }
25666            }
25667
25668            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
25669            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
25670                $(options.menu).appendTo($body);
25671            }
25672        }
25673
25674        /**
25675        * Adds internal classes to be able to provide customizable selectors
25676        * keeping the link with the style sheet.
25677        */
25678        function addInternalSelectors(){
25679            container.find(options.sectionSelector).addClass(SECTION);
25680            container.find(options.slideSelector).addClass(SLIDE);
25681        }
25682
25683        /**
25684        * Creates the control arrows for the given section
25685        */
25686        function createSlideArrows(section){
25687            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
25688
25689            if(options.controlArrowColor!='#fff'){
25690                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
25691                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
25692            }
25693
25694            if(!options.loopHorizontal){
25695                section.find(SLIDES_ARROW_PREV_SEL).hide();
25696            }
25697        }
25698
25699        /**
25700        * Creates a vertical navigation bar.
25701        */
25702        function addVerticalNavigation(){
25703            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
25704            var nav = $(SECTION_NAV_SEL);
25705
25706            nav.addClass(function() {
25707                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
25708            });
25709
25710            for (var i = 0; i < $(SECTION_SEL).length; i++) {
25711                var link = '';
25712                if (options.anchors.length) {
25713                    link = options.anchors[i];
25714                }
25715
25716                var li = '<li><a href="#' + link + '"><span></span></a>';
25717
25718                // Only add tooltip if needed (defined by user)
25719                var tooltip = options.navigationTooltips[i];
25720
25721                if (typeof tooltip !== 'undefined' && tooltip !== '') {
25722                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
25723                }
25724
25725                li += '</li>';
25726
25727                nav.find('ul').append(li);
25728            }
25729
25730            //centering it vertically
25731            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
25732
25733            //activating the current active section
25734            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
25735        }
25736
25737        /**
25738        * Creates the slim scroll scrollbar for the sections and slides inside them.
25739        */
25740        function createScrollBarHandler(){
25741            $(SECTION_SEL).each(function(){
25742                var slides = $(this).find(SLIDE_SEL);
25743
25744                if(slides.length){
25745                    slides.each(function(){
25746                        createScrollBar($(this));
25747                    });
25748                }else{
25749                    createScrollBar($(this));
25750                }
25751
25752            });
25753            afterRenderActions();
25754        }
25755
25756        /*
25757        * Enables the Youtube videos API so we can control their flow if necessary.
25758        */
25759        function enableYoutubeAPI(){
25760            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
25761                addURLParam($(this), 'enablejsapi=1');
25762            });
25763        }
25764
25765        /**
25766        * Adds a new parameter and its value to the `src` of a given element
25767        */
25768        function addURLParam(element, newParam){
25769            var originalSrc = element.attr('src');
25770            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
25771        }
25772
25773        /*
25774        * Returns the prefix sign to use for a new parameter in an existen URL.
25775        *
25776        * @return {String}  ? | &
25777        */
25778        function getUrlParamSign(url){
25779            return ( !/\?/.test( url ) ) ? '?' : '&';
25780        }
25781
25782        /**
25783        * Actions and callbacks to fire afterRender
25784        */
25785        function afterRenderActions(){
25786            var section = $(SECTION_ACTIVE_SEL);
25787
25788            section.addClass(COMPLETELY);
25789
25790            if(options.scrollOverflowHandler.afterRender){
25791                options.scrollOverflowHandler.afterRender(section);
25792            }
25793            lazyLoad(section);
25794            playMedia(section);
25795            options.scrollOverflowHandler.afterLoad();
25796
25797            if(isDestinyTheStartingSection()){
25798                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
25799            }
25800
25801            // Uncode change
25802            // $.isFunction( options.afterRender ) && options.afterRender.call(container);
25803            $.isFunction( options.afterRender ) && options.afterRender.call(container, getTableHeight());
25804        }
25805
25806        /**
25807        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
25808        */
25809        function isDestinyTheStartingSection(){
25810            var anchors =  window.location.hash.replace('#', '').split('/');
25811            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
25812
25813            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
25814        }
25815
25816
25817        var isScrolling = false;
25818        var lastScroll = 0;
25819
25820        //when scrolling...
25821        function scrollHandler(){
25822            var currentSection;
25823
25824            if(!options.autoScrolling || options.scrollBar){
25825                var currentScroll = $window.scrollTop();
25826                var scrollDirection = getScrollDirection(currentScroll);
25827                var visibleSectionIndex = 0;
25828                var screen_mid = currentScroll + ($window.height() / 2.0);
25829                var isAtBottom = $body.height() - $window.height() === currentScroll;
25830                var sections =  document.querySelectorAll(SECTION_SEL);
25831
25832                //when using `auto-height` for a small last section it won't be centered in the viewport
25833                if(isAtBottom){
25834                    visibleSectionIndex = sections.length - 1;
25835                }
25836                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
25837                else if(!currentScroll){
25838                    visibleSectionIndex = 0;
25839                }
25840
25841                //taking the section which is showing more content in the viewport
25842                else{
25843                    for (var i = 0; i < sections.length; ++i) {
25844                        var section = sections[i];
25845
25846                        // Pick the the last section which passes the middle line of the screen.
25847                        if (section.offsetTop <= screen_mid)
25848                        {
25849                            visibleSectionIndex = i;
25850                        }
25851                    }
25852                }
25853
25854                if(isCompletelyInViewPort(scrollDirection)){
25855                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
25856                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
25857                    }
25858                }
25859
25860                //geting the last one, the current one on the screen
25861                currentSection = $(sections).eq(visibleSectionIndex);
25862
25863                //setting the visible section as active when manually scrolling
25864                //executing only once the first time we reach the section
25865                if(!currentSection.hasClass(ACTIVE)){
25866                    isScrolling = true;
25867                    var leavingSection = $(SECTION_ACTIVE_SEL);
25868                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
25869                    var yMovement = getYmovement(currentSection);
25870                    var anchorLink  = currentSection.data('anchor');
25871                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
25872                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
25873                    var slideIndex;
25874                    var slideAnchorLink;
25875
25876                    if(activeSlide.length){
25877                        slideAnchorLink = activeSlide.data('anchor');
25878                        slideIndex = activeSlide.index();
25879                    }
25880
25881                    if(canScroll){
25882                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
25883
25884                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
25885                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
25886
25887                        stopMedia(leavingSection);
25888                        lazyLoad(currentSection);
25889                        playMedia(currentSection);
25890
25891                        activateMenuAndNav(anchorLink, sectionIndex - 1);
25892
25893                        if(options.anchors.length){
25894                            //needed to enter in hashChange event when using the menu with anchor links
25895                            lastScrolledDestiny = anchorLink;
25896                        }
25897                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
25898                    }
25899
25900                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
25901                    clearTimeout(scrollId);
25902                    scrollId = setTimeout(function(){
25903                        isScrolling = false;
25904                    }, 100);
25905                }
25906
25907                if(options.fitToSection){
25908                    //for the auto adjust of the viewport to fit a whole section
25909                    clearTimeout(scrollId2);
25910
25911                    scrollId2 = setTimeout(function(){
25912                        //checking it again in case it changed during the delay
25913                        if(options.fitToSection){
25914                            fitToSection();
25915                        }
25916                    }, options.fitToSectionDelay);
25917                }
25918            }
25919        }
25920
25921        /**
25922        * Fits the site to the nearest active section
25923        */
25924        function fitToSection(){
25925            //checking fitToSection again in case it was set to false before the timeout delay
25926            if(canScroll){
25927                //allows to scroll to an active section and
25928                //if the section is already active, we prevent firing callbacks
25929                isResizing = true;
25930
25931                scrollPage($(SECTION_ACTIVE_SEL));
25932                isResizing = false;
25933            }
25934        }
25935
25936        /**
25937        * Determines whether the active section has seen in its whole or not.
25938        */
25939        function isCompletelyInViewPort(movement){
25940            var top = $(SECTION_ACTIVE_SEL).position().top;
25941            var bottom = top + $window.height();
25942
25943            if(movement == 'up'){
25944                return bottom >= ($window.scrollTop() + $window.height());
25945            }
25946            return top <= $window.scrollTop();
25947        }
25948
25949        /**
25950        * Gets the directon of the the scrolling fired by the scroll event.
25951        */
25952        function getScrollDirection(currentScroll){
25953            var direction = currentScroll > lastScroll ? 'down' : 'up';
25954
25955            lastScroll = currentScroll;
25956
25957            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
25958            previousDestTop = currentScroll;
25959
25960            return direction;
25961        }
25962
25963        /**
25964        * Determines the way of scrolling up or down:
25965        * by 'automatically' scrolling a section or by using the default and normal scrolling.
25966        */
25967        function scrolling(type, scrollable){
25968            if (!isScrollAllowed.m[type]){
25969                return;
25970            }
25971            var check = (type === 'down') ? 'bottom' : 'top';
25972            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
25973
25974            if(scrollable.length > 0 ){
25975                //is the scrollbar at the start/end of the scroll?
25976                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
25977                    scrollSection();
25978                }else{
25979                    return true;
25980                }
25981            }else{
25982                // moved up/down
25983                scrollSection();
25984            }
25985        }
25986
25987        /*
25988        * Preventing bouncing in iOS #2285
25989        */
25990        function preventBouncing(event){
25991            var e = event.originalEvent;
25992            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e) && isScrollAllowed.m.up){
25993                //preventing the easing on iOS devices
25994                event.preventDefault();
25995            }
25996        }
25997
25998        var touchStartY = 0;
25999        var touchStartX = 0;
26000        var touchEndY = 0;
26001        var touchEndX = 0;
26002
26003        /* Detecting touch events
26004
26005        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
26006        * This way, the touchstart and the touch moves shows an small difference between them which is the
26007        * used one to determine the direction.
26008        */
26009        function touchMoveHandler(event){
26010            var e = event.originalEvent;
26011            var activeSection = $(e.target).closest(SECTION_SEL);
26012
26013            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
26014            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
26015
26016                if(options.autoScrolling){
26017                    //preventing the easing on iOS devices
26018                    event.preventDefault();
26019                }
26020
26021                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
26022                var touchEvents = getEventsPage(e);
26023
26024                touchEndY = touchEvents.y;
26025                touchEndX = touchEvents.x;
26026
26027                //if movement in the X axys is greater than in the Y and the currect section has slides...
26028                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
26029
26030                    //is the movement greater than the minimum resistance to scroll?
26031                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
26032                        if (touchStartX > touchEndX) {
26033                            if(isScrollAllowed.m.right){
26034                                moveSlideRight(activeSection); //next
26035                            }
26036                        } else {
26037                            if(isScrollAllowed.m.left){
26038                                moveSlideLeft(activeSection); //prev
26039                            }
26040                        }
26041                    }
26042                }
26043
26044                //vertical scrolling (only when autoScrolling is enabled)
26045                else if(options.autoScrolling && canScroll){
26046
26047                    //is the movement greater than the minimum resistance to scroll?
26048                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
26049                        if (touchStartY > touchEndY) {
26050                            scrolling('down', scrollable);
26051                        } else if (touchEndY > touchStartY) {
26052                            scrolling('up', scrollable);
26053                        }
26054                    }
26055                }
26056            }
26057        }
26058
26059        /**
26060         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
26061         * Currently works well for iOS - Android might need some testing
26062         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
26063         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
26064         * @return {boolean} true if there is a match to options.normalScrollElements
26065         */
26066        function checkParentForNormalScrollElement (el, hop) {
26067            hop = hop || 0;
26068            var parent = $(el).parent();
26069
26070            if (hop < options.normalScrollElementTouchThreshold &&
26071                parent.is(options.normalScrollElements) ) {
26072                return true;
26073            } else if (hop == options.normalScrollElementTouchThreshold) {
26074                return false;
26075            } else {
26076                return checkParentForNormalScrollElement(parent, ++hop);
26077            }
26078        }
26079
26080        /**
26081        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
26082        * this way we make sure that is really a touch event what IE is detecting.
26083        */
26084        function isReallyTouch(e){
26085            //if is not IE   ||  IE is detecting `touch` or `pen`
26086            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
26087        }
26088
26089        /**
26090        * Handler for the touch start event.
26091        */
26092        function touchStartHandler(event){
26093            var e = event.originalEvent;
26094
26095            //stopping the auto scroll to adjust to a section
26096            if(options.fitToSection){
26097                $htmlBody.stop();
26098            }
26099
26100            if(isReallyTouch(e)){
26101                var touchEvents = getEventsPage(e);
26102                touchStartY = touchEvents.y;
26103                touchStartX = touchEvents.x;
26104            }
26105        }
26106
26107        /**
26108        * Gets the average of the last `number` elements of the given array.
26109        */
26110        function getAverage(elements, number){
26111            var sum = 0;
26112
26113            //taking `number` elements from the end to make the average, if there are not enought, 1
26114            var lastElements = elements.slice(Math.max(elements.length - number, 1));
26115
26116            for(var i = 0; i < lastElements.length; i++){
26117                sum = sum + lastElements[i];
26118            }
26119
26120            return Math.ceil(sum/number);
26121        }
26122
26123        /**
26124         * Detecting mousewheel scrolling
26125         *
26126         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
26127         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
26128         */
26129        var prevTime = new Date().getTime();
26130
26131        function MouseWheelHandler(e) {
26132            var curTime = new Date().getTime();
26133            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
26134
26135            //autoscrolling and not zooming?
26136            if(options.autoScrolling && !controlPressed && !isNormalScroll){
26137                // cross-browser wheel delta
26138                e = e || window.event;
26139                var value = e.wheelDelta || -e.deltaY || -e.detail;
26140                var delta = Math.max(-1, Math.min(1, value));
26141
26142                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
26143                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
26144
26145                //Limiting the array to 150 (lets not waste memory!)
26146                if(scrollings.length > 149){
26147                    scrollings.shift();
26148                }
26149
26150                //keeping record of the previous scrollings
26151                scrollings.push(Math.abs(value));
26152
26153                //preventing to scroll the site on mouse wheel when scrollbar is present
26154                if(options.scrollBar){
26155                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
26156                }
26157
26158                var activeSection = $(SECTION_ACTIVE_SEL);
26159                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
26160
26161                //time difference between the last scroll and the current one
26162                var timeDiff = curTime-prevTime;
26163                prevTime = curTime;
26164
26165                //haven't they scrolled in a while?
26166                //(enough to be consider a different scrolling action to scroll another section)
26167                if(timeDiff > 200){
26168                    //emptying the array, we dont care about old scrollings for our averages
26169                    scrollings = [];
26170                }
26171
26172                if(canScroll){
26173                    var averageEnd = getAverage(scrollings, 10);
26174                    var averageMiddle = getAverage(scrollings, 70);
26175                    var isAccelerating = averageEnd >= averageMiddle;
26176
26177                    //to avoid double swipes...
26178                    if(isAccelerating && isScrollingVertically){
26179                        //scrolling down?
26180                        if (delta < 0) {
26181                            scrolling('down', scrollable);
26182
26183                        //scrolling up?
26184                        }else {
26185                            scrolling('up', scrollable);
26186                        }
26187                    }
26188                }
26189
26190                return false;
26191            }
26192
26193            if(options.fitToSection){
26194                //stopping the auto scroll to adjust to a section
26195                $htmlBody.stop();
26196            }
26197        }
26198
26199        /**
26200        * Slides a slider to the given direction.
26201        * Optional `section` param.
26202        */
26203        function moveSlide(direction, section){
26204            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
26205            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
26206            var numSlides = slides.find(SLIDE_SEL).length;
26207
26208            // more than one slide needed and nothing should be sliding
26209            if (!slides.length || slideMoving || numSlides < 2) {
26210                return;
26211            }
26212
26213            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
26214            var destiny = null;
26215
26216            if(direction === 'left'){
26217                destiny = currentSlide.prev(SLIDE_SEL);
26218            }else{
26219                destiny = currentSlide.next(SLIDE_SEL);
26220            }
26221
26222            //isn't there a next slide in the secuence?
26223            if(!destiny.length){
26224                //respect loopHorizontal settin
26225                if (!options.loopHorizontal) return;
26226
26227                if(direction === 'left'){
26228                    destiny = currentSlide.siblings(':last');
26229                }else{
26230                    destiny = currentSlide.siblings(':first');
26231                }
26232            }
26233
26234            slideMoving = true;
26235
26236            landscapeScroll(slides, destiny, direction);
26237        }
26238
26239        /**
26240        * Maintains the active slides in the viewport
26241        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
26242        */
26243        function keepSlidesPosition(){
26244            $(SLIDE_ACTIVE_SEL).each(function(){
26245                silentLandscapeScroll($(this), 'internal');
26246            });
26247        }
26248
26249        var previousDestTop = 0;
26250        /**
26251        * Returns the destination Y position based on the scrolling direction and
26252        * the height of the section.
26253        */
26254        function getDestinationPosition(element){
26255            var elemPosition = element.position();
26256
26257            //top of the desination will be at the top of the viewport
26258            var position = elemPosition.top;
26259            var isScrollingDown =  elemPosition.top > previousDestTop;
26260            var sectionBottom = position - windowsHeight + element.outerHeight();
26261            var bigSectionsDestination = options.bigSectionsDestination;
26262
26263            //Uncode addition
26264            var containerH = container.outerHeight();
26265            var containerPosition = container.offset();
26266
26267            //########### Commented by Uncode - START ###########
26268            //is the destination element bigger than the viewport?
26269            // if(element.outerHeight() > windowsHeight){
26270            //     //scrolling up?
26271            //     if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
26272            //         position = sectionBottom;
26273            //     }
26274            // }
26275
26276            // //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
26277            // else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
26278            //     //The bottom of the destination will be at the bottom of the viewport
26279            //     position = sectionBottom;
26280            // }
26281            //########### Commented by Uncode - END ###########
26282
26283            //Uncode addition
26284            if ( !$masthead.hasClass('menu-transparent') && $('body').hasClass('uncode-fp-menu-shrink') && !element.is(':first-child') )
26285                position += 18;
26286            if ( ( containerH + menuHeight + bodyBorder + adminBarHeight - windowsHeight ) < position || ( isResizing && element.is(':last-child') ) ) {
26287                position = sectionBottom + menuHeight + bodyBorder*2 + adminBarHeight;
26288            }
26289
26290            /*
26291            Keeping record of the last scrolled position to determine the scrolling direction.
26292            No conventional methods can be used as the scroll bar might not be present
26293            AND the section might not be active if it is auto-height and didnt reach the middle
26294            of the viewport.
26295            */
26296            previousDestTop = position;
26297            return position;
26298        }
26299
26300        /**
26301        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
26302        */
26303        function scrollPage(element, callback, isMovementUp){
26304            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
26305
26306            var dtop = getDestinationPosition(element);
26307            var slideAnchorLink;
26308            var slideIndex;
26309
26310            //local variables
26311            var v = {
26312                element: element,
26313                callback: callback,
26314                isMovementUp: isMovementUp,
26315                dtop: dtop,
26316                yMovement: getYmovement(element),
26317                anchorLink: element.data('anchor'),
26318                sectionIndex: element.index(SECTION_SEL),
26319                activeSlide: element.find(SLIDE_ACTIVE_SEL),
26320                activeSection: $(SECTION_ACTIVE_SEL),
26321                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
26322
26323                //caching the value of isResizing at the momment the function is called
26324                //because it will be checked later inside a setTimeout and the value might change
26325                localIsResizing: isResizing
26326            };
26327
26328            //quiting when destination scroll is the same as the current one
26329            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
26330
26331            if(v.activeSlide.length){
26332                slideAnchorLink = v.activeSlide.data('anchor');
26333                slideIndex = v.activeSlide.index();
26334            }
26335
26336            // If continuousVertical && we need to wrap around
26337            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
26338                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
26339                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
26340
26341                v = createInfiniteSections(v);
26342            }
26343
26344            //callback (onLeave) if the site is not just resizing and readjusting the slides
26345            if($.isFunction(options.onLeave) && !v.localIsResizing){
26346                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
26347                    return;
26348                }
26349            }
26350
26351            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
26352            if(!v.localIsResizing){
26353                stopMedia(v.activeSection);
26354            }
26355
26356            options.scrollOverflowHandler.beforeLeave();
26357            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
26358            lazyLoad(element);
26359            options.scrollOverflowHandler.onLeave();
26360
26361
26362            //preventing from activating the MouseWheelHandler event
26363            //more than once if the page is scrolling
26364            canScroll = false;
26365
26366            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
26367
26368            performMovement(v);
26369
26370            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
26371            lastScrolledDestiny = v.anchorLink;
26372
26373            //avoid firing it twice (as it does also on scroll)
26374            activateMenuAndNav(v.anchorLink, v.sectionIndex);
26375        }
26376
26377        /**
26378        * Performs the vertical movement (by CSS3 or by jQuery)
26379        */
26380        function performMovement(v){
26381            // using CSS3 translate functionality
26382            if (options.css3 && options.autoScrolling && !options.scrollBar) {
26383
26384                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
26385                // that's why we round it to 0.
26386                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
26387                transformContainer(translate3d, true);
26388
26389                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
26390                //scrollingSpeed to change in case of using silentMoveTo();
26391                if(options.scrollingSpeed){
26392                    clearTimeout(afterSectionLoadsId);
26393                    afterSectionLoadsId = setTimeout(function () {
26394                        afterSectionLoads(v);
26395                    }, options.scrollingSpeed);
26396                }else{
26397                    afterSectionLoads(v);
26398                }
26399            }
26400
26401            // using jQuery animate
26402            else{
26403                var scrollSettings = getScrollSettings(v);
26404
26405                $(scrollSettings.element).animate(
26406                    scrollSettings.options,
26407                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
26408                    if(options.scrollBar){
26409
26410                        /* Hack!
26411                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
26412                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
26413
26414                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
26415                        */
26416                        setTimeout(function(){
26417                            afterSectionLoads(v);
26418                        },30);
26419                    }else{
26420                        afterSectionLoads(v);
26421                    }
26422                });
26423            }
26424        }
26425
26426        /**
26427        * Gets the scrolling settings depending on the plugin autoScrolling option
26428        */
26429        function getScrollSettings(v){
26430            var scroll = {};
26431
26432            if(options.autoScrolling && !options.scrollBar){
26433                scroll.options = { 'top': -v.dtop};
26434                scroll.element = WRAPPER_SEL;
26435            }else{
26436                scroll.options = { 'scrollTop': v.dtop};
26437                scroll.element = 'html, body';
26438            }
26439
26440            return scroll;
26441        }
26442
26443        /**
26444        * Adds sections before or after the current one to create the infinite effect.
26445        */
26446        function createInfiniteSections(v){
26447            // Scrolling down
26448            if (!v.isMovementUp) {
26449                // Move all previous sections to after the active section
26450                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
26451            }
26452            else { // Scrolling up
26453                // Move all next sections to before the active section
26454                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
26455            }
26456
26457            // Maintain the displayed position (now that we changed the element order)
26458            silentScroll($(SECTION_ACTIVE_SEL).position().top);
26459
26460            // Maintain the active slides visible in the viewport
26461            keepSlidesPosition();
26462
26463            // save for later the elements that still need to be reordered
26464            v.wrapAroundElements = v.activeSection;
26465
26466            // Recalculate animation variables
26467            v.dtop = v.element.position().top;
26468            v.yMovement = getYmovement(v.element);
26469
26470            return v;
26471        }
26472
26473        /**
26474        * Fix section order after continuousVertical changes have been animated
26475        */
26476        function continuousVerticalFixSectionOrder (v) {
26477            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
26478            // finish moving the elements around so the direct navigation will function more simply
26479            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
26480                return;
26481            }
26482
26483            if (v.isMovementUp) {
26484                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
26485            }
26486            else {
26487                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
26488            }
26489
26490            silentScroll($(SECTION_ACTIVE_SEL).position().top);
26491
26492            // Maintain the active slides visible in the viewport
26493            keepSlidesPosition();
26494        }
26495
26496
26497        /**
26498        * Actions to do once the section is loaded.
26499        */
26500        function afterSectionLoads (v){
26501            continuousVerticalFixSectionOrder(v);
26502
26503            //callback (afterLoad) if the site is not just resizing and readjusting the slides
26504            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
26505            options.scrollOverflowHandler.afterLoad();
26506
26507            if(!v.localIsResizing){
26508                playMedia(v.element);
26509            }
26510
26511            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
26512
26513            canScroll = true;
26514
26515            $.isFunction(v.callback) && v.callback.call(this);
26516        }
26517
26518        /**
26519        * Sets the value for the given attribute from the `data-` attribute with the same suffix
26520        * ie: data-srcset ==> srcset  |  data-src ==> src
26521        */
26522        function setSrc(element, attribute){
26523            element
26524                .attr(attribute, element.data(attribute))
26525                .removeAttr('data-' + attribute);
26526        }
26527
26528        /**
26529        * Lazy loads image, video and audio elements.
26530        */
26531        function lazyLoad(destiny){
26532            if (!options.lazyLoading){
26533                return;
26534            }
26535
26536            var panel = getSlideOrSection(destiny);
26537            var element;
26538
26539            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
26540                element = $(this);
26541
26542                $.each(['src', 'srcset'], function(index, type){
26543                    var attribute = element.attr('data-' + type);
26544                    if(typeof attribute !== 'undefined' && attribute){
26545                        setSrc(element, type);
26546                    }
26547                });
26548
26549                if(element.is('source')){
26550                    element.closest('video').get(0).load();
26551                }
26552            });
26553        }
26554
26555        /**
26556        * Plays video and audio elements.
26557        */
26558        function playMedia(destiny){
26559            var panel = getSlideOrSection(destiny);
26560
26561            //playing HTML5 media elements
26562            panel.find('video, audio').each(function(){
26563                var element = $(this).get(0);
26564
26565                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
26566                    element.play();
26567                }
26568            });
26569
26570            //youtube videos
26571            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
26572                var element = $(this).get(0);
26573
26574                if ( element.hasAttribute('data-autoplay') ){
26575                    playYoutube(element);
26576                }
26577
26578                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
26579                element.onload = function() {
26580                    if ( element.hasAttribute('data-autoplay') ){
26581                        playYoutube(element);
26582                    }
26583                };
26584            });
26585        }
26586
26587        /**
26588        * Plays a youtube video
26589        */
26590        function playYoutube(element){
26591            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
26592        }
26593
26594        /**
26595        * Stops video and audio elements.
26596        */
26597        function stopMedia(destiny){
26598            var panel = getSlideOrSection(destiny);
26599
26600            //stopping HTML5 media elements
26601            panel.find('video, audio').each(function(){
26602                var element = $(this).get(0);
26603
26604                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
26605                    element.pause();
26606                }
26607            });
26608
26609            //youtube videos
26610            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
26611                var element = $(this).get(0);
26612
26613                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
26614                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
26615                }
26616            });
26617        }
26618
26619        /**
26620        * Gets the active slide (or section) for the given section
26621        */
26622        function getSlideOrSection(destiny){
26623            var slide = destiny.find(SLIDE_ACTIVE_SEL);
26624            if( slide.length ) {
26625                destiny = $(slide);
26626            }
26627
26628            return destiny;
26629        }
26630
26631        /**
26632        * Scrolls to the anchor in the URL when loading the site
26633        */
26634        function scrollToAnchor(){
26635            //getting the anchor link in the URL and deleting the `#`
26636            var value =  window.location.hash.replace('#', '').split('/');
26637            var sectionAnchor = decodeURIComponent(value[0]);
26638            var slideAnchor = decodeURIComponent(value[1]);
26639
26640            if(sectionAnchor){  //if theres any #
26641                if(options.animateAnchor){
26642                    scrollPageAndSlide(sectionAnchor, slideAnchor);
26643                }else{
26644                    silentMoveTo(sectionAnchor, slideAnchor);
26645                }
26646            }
26647        }
26648
26649        /**
26650        * Detecting any change on the URL to scroll to the given anchor link
26651        * (a way to detect back history button as we play with the hashes on the URL)
26652        */
26653        function hashChangeHandler(){
26654            if(!isScrolling && !options.lockAnchors){
26655                var value =  window.location.hash.replace('#', '').split('/');
26656                var sectionAnchor = decodeURIComponent(value[0]);
26657                var slideAnchor = decodeURIComponent(value[1]);
26658
26659                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
26660                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
26661                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
26662
26663
26664                if(sectionAnchor.length){
26665                    /*in order to call scrollpage() only once for each destination at a time
26666                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
26667                    event is fired on every scroll too.*/
26668                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
26669                        scrollPageAndSlide(sectionAnchor, slideAnchor);
26670                    }
26671                }
26672            }
26673        }
26674
26675        //Sliding with arrow keys, both, vertical and horizontal
26676        function keydownHandler(e) {
26677
26678            clearTimeout(keydownId);
26679
26680            var activeElement = $(':focus');
26681
26682            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
26683                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
26684                options.keyboardScrolling && options.autoScrolling){
26685                var keyCode = e.which;
26686
26687                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
26688                var keyControls = [40, 38, 32, 33, 34];
26689                if($.inArray(keyCode, keyControls) > -1){
26690                    e.preventDefault();
26691                }
26692
26693                controlPressed = e.ctrlKey;
26694
26695                keydownId = setTimeout(function(){
26696                    onkeydown(e);
26697                },150);
26698            }
26699        }
26700
26701        function tooltipTextHandler(){
26702            $(this).prev().trigger('click');
26703        }
26704
26705        //to prevent scrolling while zooming
26706        function keyUpHandler(e){
26707            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
26708                controlPressed = e.ctrlKey;
26709            }
26710        }
26711
26712        //binding the mousemove when the mouse's middle button is released
26713        function mouseDownHandler(e){
26714            //middle button
26715            if (e.which == 2){
26716                oldPageY = e.pageY;
26717                container.on('mousemove', mouseMoveHandler);
26718            }
26719        }
26720
26721        //unbinding the mousemove when the mouse's middle button is released
26722        function mouseUpHandler(e){
26723            //middle button
26724            if (e.which == 2){
26725                container.off('mousemove');
26726            }
26727        }
26728
26729        //Scrolling horizontally when clicking on the slider controls.
26730        function slideArrowHandler(){
26731            var section = $(this).closest(SECTION_SEL);
26732
26733            if ($(this).hasClass(SLIDES_PREV)) {
26734                if(isScrollAllowed.m.left){
26735                    moveSlideLeft(section);
26736                }
26737            } else {
26738                if(isScrollAllowed.m.right){
26739                    moveSlideRight(section);
26740                }
26741            }
26742        }
26743
26744        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
26745        function blurHandler(){
26746            isWindowFocused = false;
26747            controlPressed = false;
26748        }
26749
26750        //Scrolls to the section when clicking the navigation bullet
26751        function sectionBulletHandler(e){
26752            e.preventDefault();
26753            var index = $(this).parent().index();
26754            scrollPage($(SECTION_SEL).eq(index));
26755        }
26756
26757        //Scrolls the slider to the given slide destination for the given section
26758        function slideBulletHandler(e){
26759            e.preventDefault();
26760            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
26761            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
26762
26763            landscapeScroll(slides, destiny);
26764        }
26765
26766        /**
26767        * Keydown event
26768        */
26769        function onkeydown(e){
26770            var shiftPressed = e.shiftKey;
26771
26772            //do nothing if we can not scroll or we are not using horizotnal key arrows.
26773            if(!canScroll && [37,39].indexOf(e.which) < 0){
26774                return;
26775            }
26776
26777            switch (e.which) {
26778                //up
26779                case 38:
26780                case 33:
26781                    if(isScrollAllowed.k.up){
26782                        moveSectionUp();
26783                    }
26784                    break;
26785
26786                //down
26787                case 32: //spacebar
26788                    if(shiftPressed && isScrollAllowed.k.up){
26789                        moveSectionUp();
26790                        break;
26791                    }
26792                /* falls through */
26793                case 40:
26794                case 34:
26795                    if(isScrollAllowed.k.down){
26796                        moveSectionDown();
26797                    }
26798                    break;
26799
26800                //Home
26801                case 36:
26802                    if(isScrollAllowed.k.up){
26803                        moveTo(1);
26804                    }
26805                    break;
26806
26807                //End
26808                case 35:
26809                     if(isScrollAllowed.k.down){
26810                        moveTo( $(SECTION_SEL).length );
26811                    }
26812                    break;
26813
26814                //left
26815                case 37:
26816                    if(isScrollAllowed.k.left){
26817                        moveSlideLeft();
26818                    }
26819                    break;
26820
26821                //right
26822                case 39:
26823                    if(isScrollAllowed.k.right){
26824                        moveSlideRight();
26825                    }
26826                    break;
26827
26828                default:
26829                    return; // exit this handler for other keys
26830            }
26831        }
26832
26833        /**
26834        * Detecting the direction of the mouse movement.
26835        * Used only for the middle button of the mouse.
26836        */
26837        var oldPageY = 0;
26838        function mouseMoveHandler(e){
26839            if(canScroll){
26840                // moving up
26841                if (e.pageY < oldPageY && isScrollAllowed.m.up){
26842                    moveSectionUp();
26843                }
26844
26845                // moving down
26846                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
26847                    moveSectionDown();
26848                }
26849            }
26850            oldPageY = e.pageY;
26851        }
26852
26853        /**
26854        * Scrolls horizontal sliders.
26855        */
26856        function landscapeScroll(slides, destiny, direction){
26857            var section = slides.closest(SECTION_SEL);
26858            var v = {
26859                slides: slides,
26860                destiny: destiny,
26861                direction: direction,
26862                destinyPos: destiny.position(),
26863                slideIndex: destiny.index(),
26864                section: section,
26865                sectionIndex: section.index(SECTION_SEL),
26866                anchorLink: section.data('anchor'),
26867                slidesNav: section.find(SLIDES_NAV_SEL),
26868                slideAnchor:  getAnchor(destiny),
26869                prevSlide: section.find(SLIDE_ACTIVE_SEL),
26870                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
26871
26872                //caching the value of isResizing at the momment the function is called
26873                //because it will be checked later inside a setTimeout and the value might change
26874                localIsResizing: isResizing
26875            };
26876            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
26877            v.direction = v.direction ? v.direction : v.xMovement;
26878
26879            //important!! Only do it when not resizing
26880            if(!v.localIsResizing){
26881                //preventing from scrolling to the next/prev section when using scrollHorizontally
26882                canScroll = false;
26883            }
26884
26885            if(options.onSlideLeave){
26886
26887                //if the site is not just resizing and readjusting the slides
26888                if(!v.localIsResizing && v.xMovement!=='none'){
26889                    if($.isFunction( options.onSlideLeave )){
26890                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
26891                            slideMoving = false;
26892                            return;
26893                        }
26894                    }
26895                }
26896            }
26897
26898            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
26899
26900            if(!v.localIsResizing){
26901                stopMedia(v.prevSlide);
26902                lazyLoad(destiny);
26903            }
26904
26905            if(!options.loopHorizontal && options.controlArrows){
26906                //hidding it for the fist slide, showing for the rest
26907                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
26908
26909                //hidding it for the last slide, showing for the rest
26910                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
26911            }
26912
26913            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
26914            if(section.hasClass(ACTIVE) && !v.localIsResizing){
26915                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
26916            }
26917
26918            performHorizontalMove(slides, v, true);
26919        }
26920
26921
26922        function afterSlideLoads(v){
26923            activeSlidesNavigation(v.slidesNav, v.slideIndex);
26924
26925            //if the site is not just resizing and readjusting the slides
26926            if(!v.localIsResizing){
26927                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
26928
26929                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
26930                //and to prevent double scroll right after a windows resize
26931                canScroll = true;
26932
26933                playMedia(v.destiny);
26934            }
26935
26936            //letting them slide again
26937            slideMoving = false;
26938        }
26939
26940        /**
26941        * Performs the horizontal movement. (CSS3 or jQuery)
26942        *
26943        * @param fireCallback {Bool} - determines whether or not to fire the callback
26944        */
26945        function performHorizontalMove(slides, v, fireCallback){
26946            var destinyPos = v.destinyPos;
26947
26948            if(options.css3){
26949                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
26950
26951                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d), v);
26952
26953                afterSlideLoadsId = setTimeout(function(){
26954                    fireCallback && afterSlideLoads(v);
26955                }, options.scrollingSpeed, options.easing);
26956            }else{
26957                slides.animate({
26958                    scrollLeft : Math.round(destinyPos.left)
26959                }, options.scrollingSpeed, options.easing, function() {
26960
26961                    fireCallback && afterSlideLoads(v);
26962                });
26963            }
26964        }
26965
26966        /**
26967        * Sets the state for the horizontal bullet navigations.
26968        */
26969        function activeSlidesNavigation(slidesNav, slideIndex){
26970            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
26971            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
26972        }
26973
26974        var previousHeight = windowsHeight;
26975
26976        //when resizing the site, we adjust the heights of the sections, slimScroll...
26977        function resizeHandler(){
26978            //checking if it needs to get responsive
26979            responsive();
26980
26981            // rebuild immediately on touch devices
26982            if (isTouchDevice) {
26983                var activeElement = $(document.activeElement);
26984
26985                //if the keyboard is NOT visible
26986                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
26987                    var currentHeight = $window.height();
26988
26989                    //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)
26990                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
26991                        reBuild(true);
26992                        previousHeight = currentHeight;
26993                    }
26994                }
26995            }else{
26996                //in order to call the functions only when the resize is finished
26997                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
26998                clearTimeout(resizeId);
26999
27000                resizeId = setTimeout(function(){
27001                    reBuild(true);
27002                }, 350);
27003            }
27004        }
27005
27006        /**
27007        * Checks if the site needs to get responsive and disables autoScrolling if so.
27008        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
27009        */
27010        function responsive(){
27011            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
27012            var heightLimit = options.responsiveHeight;
27013
27014            //only calculating what we need. Remember its called on the resize event.
27015            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
27016            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
27017
27018            if(widthLimit && heightLimit){
27019                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
27020            }
27021            else if(widthLimit){
27022                setResponsive(isBreakingPointWidth);
27023            }
27024            else if(heightLimit){
27025                setResponsive(isBreakingPointHeight);
27026            }
27027        }
27028
27029        /**
27030        * Adds transition animations for the given element
27031        */
27032        function addAnimation(container, element){
27033            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
27034
27035            container.removeClass(NO_TRANSITION);
27036            return container.css({
27037                '-webkit-transition': transition,
27038                'transition': transition
27039            });
27040        }
27041
27042        /**
27043        * Remove transition animations for the given element
27044        */
27045        function removeAnimation(element){
27046            return element.addClass(NO_TRANSITION);
27047        }
27048
27049        /**
27050        * Activating the vertical navigation bullets according to the given slide name.
27051        */
27052        function activateNavDots(name, sectionIndex){
27053            if(options.navigation){
27054                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
27055                if(name){
27056                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
27057                }else{
27058                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
27059                }
27060            }
27061        }
27062
27063        /**
27064        * Activating the website main menu elements according to the given slide name.
27065        */
27066        function activateMenuElement(name){
27067            if(options.menu){
27068                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
27069                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
27070            }
27071        }
27072
27073        /**
27074        * Sets to active the current menu and vertical nav items.
27075        */
27076        function activateMenuAndNav(anchor, index){
27077            activateMenuElement(anchor);
27078            activateNavDots(anchor, index);
27079        }
27080
27081        /**
27082        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
27083        * from the current section.
27084        */
27085        function getYmovement(destiny){
27086            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
27087            var toIndex = destiny.index(SECTION_SEL);
27088            if( fromIndex == toIndex){
27089                return 'none';
27090            }
27091            if(fromIndex > toIndex){
27092                return 'up';
27093            }
27094            return 'down';
27095        }
27096
27097        /**
27098        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
27099        * from the current slide.
27100        */
27101        function getXmovement(fromIndex, toIndex){
27102            if( fromIndex == toIndex){
27103                return 'none';
27104            }
27105            if(fromIndex > toIndex){
27106                return 'left';
27107            }
27108            return 'right';
27109        }
27110
27111        /**
27112        * Checks if the element needs scrollbar and if the user wants to apply it.
27113        * If so it creates it.
27114        *
27115        * @param {Object} element   jQuery object of the section or slide
27116        */
27117        function createScrollBar(element){
27118            //User doesn't want scrollbar here? Sayonara baby!
27119            if(element.hasClass('fp-noscroll')) return;
27120
27121            //needed to make `scrollHeight` work under Opera 12
27122            element.css('overflow', 'hidden');
27123
27124            var scrollOverflowHandler = options.scrollOverflowHandler;
27125            var wrap = scrollOverflowHandler.wrapContent();
27126            //in case element is a slide
27127            var section = element.closest(SECTION_SEL);
27128            var scrollable = scrollOverflowHandler.scrollable(element);
27129            var contentHeight;
27130
27131            //if there was scroll, the contentHeight will be the one in the scrollable section
27132            if(scrollable.length){
27133                contentHeight = scrollOverflowHandler.scrollHeight(element);
27134            }else{
27135                contentHeight = element.get(0).scrollHeight;
27136                if(options.verticalCentered){
27137                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
27138                }
27139            }
27140
27141            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
27142
27143            //needs scroll?
27144            if ( contentHeight > scrollHeight) {
27145                //did we already have an scrollbar ? Updating it
27146                if(scrollable.length){
27147                    scrollOverflowHandler.update(element, scrollHeight);
27148                }
27149                //creating the scrolling
27150                else{
27151                    if(options.verticalCentered){
27152                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
27153                    }else{
27154                        element.wrapInner(wrap);
27155                    }
27156                    scrollOverflowHandler.create(element, scrollHeight);
27157                }
27158            }
27159            //removing the scrolling when it is not necessary anymore
27160            else{
27161                scrollOverflowHandler.remove(element);
27162            }
27163
27164            //undo
27165            element.css('overflow', '');
27166        }
27167
27168        function addTableClass(element){
27169            //In case we are styling for the 2nd time as in with reponsiveSlides
27170            if(!element.hasClass(TABLE)){
27171                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
27172            }
27173        }
27174
27175        function getTableHeight(element){
27176            var sectionHeight = windowsHeight;
27177
27178            if(options.paddingTop || options.paddingBottom){
27179                var section = element;
27180                if(!section.hasClass(SECTION)){
27181                    section = element.closest(SECTION_SEL);
27182                }
27183
27184                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
27185                sectionHeight = (windowsHeight - paddings);
27186            }
27187
27188            return sectionHeight;
27189        }
27190
27191        /**
27192        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
27193        */
27194        function transformContainer(translate3d, animated){
27195            if(animated){
27196                addAnimation(container);
27197            }else{
27198                removeAnimation(container);
27199            }
27200
27201            container.css(getTransforms(translate3d));
27202
27203            //syncronously removing the class after the animation has been applied.
27204            setTimeout(function(){
27205                container.removeClass(NO_TRANSITION);
27206            },10);
27207        }
27208
27209        /**
27210        * Gets a section by its anchor / index
27211        */
27212        function getSectionByAnchor(sectionAnchor){
27213            if(!sectionAnchor) return [];
27214
27215            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
27216            if(!section.length){
27217                section = $(SECTION_SEL).eq( sectionAnchor -1);
27218            }
27219
27220            return section;
27221        }
27222
27223        /**
27224        * Gets a slide inside a given section by its anchor / index
27225        */
27226        function getSlideByAnchor(slideAnchor, section){
27227            var slides = section.find(SLIDES_WRAPPER_SEL);
27228            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
27229
27230            if(!slide.length){
27231                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
27232            }
27233
27234            return slide;
27235        }
27236
27237        /**
27238        * Scrolls to the given section and slide anchors
27239        */
27240        function scrollPageAndSlide(destiny, slide){
27241            var section = getSectionByAnchor(destiny);
27242
27243            //do nothing if there's no section with the given anchor name
27244            if(!section.length) return;
27245
27246            //default slide
27247            if (typeof slide === 'undefined') {
27248                slide = 0;
27249            }
27250
27251            //we need to scroll to the section and then to the slide
27252            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
27253                scrollPage(section, function(){
27254                    scrollSlider(section, slide);
27255                });
27256            }
27257            //if we were already in the section
27258            else{
27259                scrollSlider(section, slide);
27260            }
27261        }
27262
27263        /**
27264        * Scrolls the slider to the given slide destination for the given section
27265        */
27266        function scrollSlider(section, slideAnchor){
27267            if(typeof slideAnchor !== 'undefined'){
27268                var slides = section.find(SLIDES_WRAPPER_SEL);
27269                var destiny =  getSlideByAnchor(slideAnchor, section);
27270
27271                if(destiny.length){
27272                    landscapeScroll(slides, destiny);
27273                }
27274            }
27275        }
27276
27277        /**
27278        * Creates a landscape navigation bar with dots for horizontal sliders.
27279        */
27280        function addSlidesNavigation(section, numSlides){
27281            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
27282            var nav = section.find(SLIDES_NAV_SEL);
27283
27284            //top or bottom
27285            nav.addClass(options.slidesNavPosition);
27286
27287            for(var i=0; i< numSlides; i++){
27288                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
27289            }
27290
27291            //centering it
27292            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
27293
27294            nav.find('li').first().find('a').addClass(ACTIVE);
27295        }
27296
27297
27298        /**
27299        * Sets the state of the website depending on the active section/slide.
27300        * It changes the URL hash when needed and updates the body class.
27301        */
27302        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
27303            var sectionHash = '';
27304
27305            if(options.anchors.length && !options.lockAnchors){
27306
27307                //isn't it the first slide?
27308                if(slideIndex){
27309                    if(typeof anchorLink !== 'undefined'){
27310                        sectionHash = anchorLink;
27311                    }
27312
27313                    //slide without anchor link? We take the index instead.
27314                    if(typeof slideAnchor === 'undefined'){
27315                        slideAnchor = slideIndex;
27316                    }
27317
27318                    lastScrolledSlide = slideAnchor;
27319                    setUrlHash(sectionHash + '/' + slideAnchor);
27320
27321                //first slide won't have slide anchor, just the section one
27322                }else if(typeof slideIndex !== 'undefined'){
27323                    lastScrolledSlide = slideAnchor;
27324                    setUrlHash(anchorLink);
27325                }
27326
27327                //section without slides
27328                else{
27329                    setUrlHash(anchorLink);
27330                }
27331            }
27332
27333            setBodyClass();
27334        }
27335
27336        /**
27337        * Sets the URL hash.
27338        */
27339        function setUrlHash(url){
27340            //Uncode addition
27341            if ( typeof SiteParameters.slide_footer != 'undefined' && url == SiteParameters.slide_footer )
27342                return false;
27343
27344            if(options.recordHistory){
27345                location.hash = url;
27346            }else{
27347                //Uncode addition
27348                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
27349                // if(isTouchDevice || isTouch){
27350                //     window.history.replaceState(undefined, undefined, '#' + url);
27351                // }else{
27352                //     var baseUrl = window.location.href.split('#')[0];
27353                //     window.location.replace( baseUrl + '#' + url );
27354                // }
27355                return false;
27356            }
27357        }
27358
27359        /**
27360        * Gets the anchor for the given slide / section. Its index will be used if there's none.
27361        */
27362        function getAnchor(element){
27363            var anchor = element.data('anchor');
27364            var index = element.index();
27365
27366            //Slide without anchor link? We take the index instead.
27367            if(typeof anchor === 'undefined'){
27368                anchor = index;
27369            }
27370
27371            return anchor;
27372        }
27373
27374        /**
27375        * Sets a class for the body of the page depending on the active section / slide
27376        */
27377        function setBodyClass(){
27378            var section = $(SECTION_ACTIVE_SEL);
27379            var slide = section.find(SLIDE_ACTIVE_SEL);
27380
27381            var sectionAnchor = getAnchor(section);
27382            var slideAnchor = getAnchor(slide);
27383
27384            var text = String(sectionAnchor);
27385
27386            if(slide.length){
27387                text = text + '-' + slideAnchor;
27388            }
27389
27390            //changing slash for dash to make it a valid CSS style
27391            text = text.replace('/', '-').replace('#','');
27392
27393            //removing previous anchor classes
27394            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
27395            $body[0].className = $body[0].className.replace(classRe, '');
27396
27397            //adding the current anchor
27398            $body.addClass(VIEWING_PREFIX + '-' + text);
27399        }
27400
27401        /**
27402        * Checks for translate3d support
27403        * @return boolean
27404        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
27405        */
27406        function support3d() {
27407            var el = document.createElement('p'),
27408                has3d,
27409                transforms = {
27410                    'webkitTransform':'-webkit-transform',
27411                    'OTransform':'-o-transform',
27412                    'msTransform':'-ms-transform',
27413                    'MozTransform':'-moz-transform',
27414                    'transform':'transform'
27415                };
27416
27417            // Add it to the body to get the computed style.
27418            document.body.insertBefore(el, null);
27419
27420            for (var t in transforms) {
27421                if (el.style[t] !== undefined) {
27422                    el.style[t] = 'translate3d(1px,1px,1px)';
27423                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
27424                }
27425            }
27426
27427            document.body.removeChild(el);
27428
27429            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
27430        }
27431
27432        /**
27433        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
27434        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
27435        */
27436        function removeMouseWheelHandler(){
27437            if (document.addEventListener) {
27438                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
27439                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
27440                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
27441            } else {
27442                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
27443            }
27444        }
27445
27446        /**
27447        * Adds the auto scrolling action for the mouse wheel and trackpad.
27448        * After this function is called, the mousewheel and trackpad movements will scroll through sections
27449        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
27450        */
27451        function addMouseWheelHandler(){
27452            var prefix = '';
27453            var _addEventListener;
27454
27455            if (window.addEventListener){
27456                _addEventListener = "addEventListener";
27457            }else{
27458                _addEventListener = "attachEvent";
27459                prefix = 'on';
27460            }
27461
27462             // detect available wheel event
27463            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
27464                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
27465                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
27466            var passiveEvent = g_supportsPassive ? {passive: false }
27466: false;
27467
27468
27469            if(support == 'DOMMouseScroll'){
27470                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, passiveEvent);
27471            }
27472
27473            //handle MozMousePixelScroll in older Firefox
27474            else{
27475                document[ _addEventListener ](prefix + support, MouseWheelHandler, passiveEvent);
27476            }
27477        }
27478
27479        /**
27480        * Binding the mousemove when the mouse's middle button is pressed
27481        */
27482        function addMiddleWheelHandler(){
27483            container
27484                .on('mousedown', mouseDownHandler)
27485                .on('mouseup', mouseUpHandler);
27486        }
27487
27488        /**
27489        * Unbinding the mousemove when the mouse's middle button is released
27490        */
27491        function removeMiddleWheelHandler(){
27492            container
27493                .off('mousedown', mouseDownHandler)
27494                .off('mouseup', mouseUpHandler);
27495        }
27496
27497        /**
27498        * Adds the possibility to auto scroll through sections on touch devices.
27499        */
27500        function addTouchHandler(){
27501            if(isTouchDevice || isTouch){
27502                if(options.autoScrolling){
27503                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
27504                }
27505
27506                $(WRAPPER_SEL)
27507                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
27508                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
27509            }
27510        }
27511
27512        /**
27513        * Removes the auto scrolling for touch devices.
27514        */
27515        function removeTouchHandler(){
27516            if(isTouchDevice || isTouch){
27517                $(WRAPPER_SEL)
27518                    .off(events.touchstart)
27519                    .off(events.touchmove);
27520            }
27521        }
27522
27523        /*
27524        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
27525        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
27526        */
27527        function getMSPointer(){
27528            var pointer;
27529
27530            //IE >= 11 & rest of browsers
27531            if(window.PointerEvent){
27532                pointer = { down: 'pointerdown', move: 'pointermove'};
27533            }
27534
27535            //IE < 11
27536            else{
27537                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
27538            }
27539
27540            return pointer;
27541        }
27542
27543        /**
27544        * Gets the pageX and pageY properties depending on the browser.
27545        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
27546        */
27547        function getEventsPage(e){
27548            var events = [];
27549
27550            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
27551            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
27552
27553            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
27554            if(isTouch && isReallyTouch(e) && options.scrollBar){
27555                events.y = e.touches[0].pageY;
27556                events.x = e.touches[0].pageX;
27557            }
27558
27559            return events;
27560        }
27561
27562        /**
27563        * Slides silently (with no animation) the active slider to the given slide.
27564        * @param noCallback {bool} true or defined -> no callbacks
27565        */
27566        function silentLandscapeScroll(activeSlide, noCallbacks){
27567            setScrollingSpeed (0, 'internal');
27568
27569            if(typeof noCallbacks !== 'undefined'){
27570                //preventing firing callbacks afterSlideLoad etc.
27571                isResizing = true;
27572            }
27573
27574            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
27575
27576            if(typeof noCallbacks !== 'undefined'){
27577                isResizing = false;
27578            }
27579
27580            setScrollingSpeed(originals.scrollingSpeed, 'internal');
27581        }
27582
27583        /**
27584        * Scrolls silently (with no animation) the page to the given Y position.
27585        */
27586        function silentScroll(top){
27587            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
27588            // that's why we round it to 0.
27589            var roundedTop = Math.round(top);
27590
27591            if (options.css3 && options.autoScrolling && !options.scrollBar){
27592                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
27593                transformContainer(translate3d, false);
27594            }
27595            else if(options.autoScrolling && !options.scrollBar){
27596                container.css('top', -roundedTop);
27597            }
27598            else{
27599                $htmlBody.scrollTop(roundedTop);
27600            }
27601        }
27602
27603        /**
27604        * Returns the cross-browser transform string.
27605        */
27606        function getTransforms(translate3d){
27607            return {
27608                '-webkit-transform': translate3d,
27609                '-moz-transform': translate3d,
27610                '-ms-transform':translate3d,
27611                'transform': translate3d
27612            };
27613        }
27614
27615        /**
27616        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
27617        * @type  m (mouse) or k (keyboard)
27618        */
27619        function setIsScrollAllowed(value, direction, type){
27620            switch (direction){
27621                case 'up': isScrollAllowed[type].up = value; break;
27622                case 'down': isScrollAllowed[type].down = value; break;
27623                case 'left': isScrollAllowed[type].left = value; break;
27624                case 'right': isScrollAllowed[type].right = value; break;
27625                case 'all':
27626                    if(type == 'm'){
27627                        setAllowScrolling(value);
27628                    }else{
27629                        setKeyboardScrolling(value);
27630                    }
27631            }
27632        }
27633
27634        /*
27635        * Destroys fullpage.js plugin events and optinally its html markup and styles
27636        */
27637        function destroy(all){
27638            setAutoScrolling(false, 'internal');
27639            setAllowScrolling(false);
27640            setKeyboardScrolling(false);
27641            container.addClass(DESTROYED);
27642
27643            clearTimeout(afterSlideLoadsId);
27644            clearTimeout(afterSectionLoadsId);
27645            clearTimeout(resizeId);
27646            clearTimeout(scrollId);
27647            clearTimeout(scrollId2);
27648
27649            $window
27650                .off('scroll', scrollHandler)
27651                .off('hashchange', hashChangeHandler)
27652                .off('resize', resizeHandler);
27653
27654            $document
27655                .off('click touchstart', SECTION_NAV_SEL + ' a')
27656                .off('mouseenter', SECTION_NAV_SEL + ' li')
27657                .off('mouseleave', SECTION_NAV_SEL + ' li')
27658                .off('click touchstart', SLIDES_NAV_LINK_SEL)
27659                .off('mouseover', options.normalScrollElements)
27660                .off('mouseout', options.normalScrollElements);
27661
27662            $(SECTION_SEL)
27663                .off('click touchstart', SLIDES_ARROW_SEL);
27664
27665            clearTimeout(afterSlideLoadsId);
27666            clearTimeout(afterSectionLoadsId);
27667
27668            //lets make a mess!
27669            if(all){
27670                destroyStructure();
27671            }
27672        }
27673
27674        /*
27675        * Removes inline styles added by fullpage.js
27676        */
27677        function destroyStructure(){
27678            //reseting the `top` or `translate` properties to 0
27679            silentScroll(0);
27680
27681            //loading all the lazy load content
27682            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
27683                setSrc($(this), 'src');
27684            });
27685
27686            container.find('img[data-srcset]').each(function(){
27687                setSrc($(this), 'srcset');
27688            });
27689
27690            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
27691
27692            //removing inline styles
27693            $(SECTION_SEL).css( {
27694                'height': '',
27695                'background-color' : '',
27696                'padding': ''
27697            });
27698
27699            $(SLIDE_SEL).css( {
27700                'width': ''
27701            });
27702
27703            container.css({
27704                'height': '',
27705                'position': '',
27706                '-ms-touch-action': '',
27707                'touch-action': ''
27708            });
27709
27710            $htmlBody.css({
27711                'overflow': '',
27712                'height': ''
27713            });
27714
27715            // remove .fp-enabled class
27716            $('html').removeClass(ENABLED);
27717
27718            // remove .fp-responsive class
27719            $body.removeClass(RESPONSIVE);
27720
27721            // remove all of the .fp-viewing- classes
27722            $.each($body.get(0).className.split(/\s+/), function (index, className) {
27723                if (className.indexOf(VIEWING_PREFIX) === 0) {
27724                    $body.removeClass(className);
27725                }
27726            });
27727
27728            //removing added classes
27729            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
27730                options.scrollOverflowHandler.remove($(this));
27731                $(this).removeClass(TABLE + ' ' + ACTIVE);
27732            });
27733
27734            removeAnimation(container);
27735
27736            //Unwrapping content
27737            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
27738                //unwrap not being use in case there's no child element inside and its just text
27739                $(this).replaceWith(this.childNodes);
27740            });
27741
27742            //removing the applied transition from the fullpage wrapper
27743            container.css({
27744                '-webkit-transition': 'none',
27745                'transition': 'none'
27746            });
27747
27748            //scrolling the page to the top with no animation
27749            $htmlBody.scrollTop(0);
27750
27751            //removing selectors
27752            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
27753            $.each(usedSelectors, function(index, value){
27754                $('.' + value).removeClass(value);
27755            });
27756        }
27757
27758        /*
27759        * Sets the state for a variable with multiple states (original, and temporal)
27760        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
27761        * This function is used to keep track of both states, the original and the temporal one.
27762        * If type is not 'internal', then we assume the user is globally changing the variable.
27763        */
27764        function setVariableState(variable, value, type){
27765            options[variable] = value;
27766            if(type !== 'internal'){
27767                originals[variable] = value;
27768            }
27769        }
27770
27771        /**
27772        * Displays warnings
27773        */
27774        function displayWarnings(){
27775            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
27776            //UNCODE.addition
27777            // if($('html').hasClass(ENABLED)){
27778            //     showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
27779            //     return;
27780            // }
27781
27782            // Disable mutually exclusive settings
27783            //UNCODE.addition
27784            // if (options.continuousVertical &&
27785            //     (options.loopTop || options.loopBottom)) {
27786            //     options.continuousVertical = false;
27787            //     showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
27788            // }
27789
27790            // if(options.scrollBar && options.scrollOverflow){
27791            //     showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
27792            // }
27793
27794            // if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
27795            //     options.continuousVertical = false;
27796            //     showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
27797            // }
27798
27799            //using extensions? Wrong file!
27800            $.each(extensions, function(index, extension){
27801                //is the option set to true?
27802                if(options[extension]){
27803                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
27804                }
27805            });
27806
27807            //anchors can not have the same value as any element ID or NAME
27808            $.each(options.anchors, function(index, name){
27809
27810                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
27811                var nameAttr = $document.find('[name]').filter(function() {
27812                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
27813                });
27814
27815                var idAttr = $document.find('[id]').filter(function() {
27816                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
27817                });
27818
27819                if(idAttr.length || nameAttr.length ){
27820                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
27821                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
27822                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
27823                }
27824            });
27825        }
27826
27827        /**
27828        * Shows a message in the console of the given type.
27829        */
27830        function showError(type, text){
27831            console && console[type] && console[type]('fullPage: ' + text);
27832        }
27833
27834    }; //end of $.fn.fullpage
27835
27836    if(typeof IScroll !== 'undefined'){
27837        /*
27838        * Turns iScroll `mousewheel` option off dynamically
27839        * https://github.com/cubiq/iscroll/issues/1036
27840        */
27841        IScroll.prototype.wheelOn = function () {
27842            this.wrapper.addEventListener('wheel', this);
27843            this.wrapper.addEventListener('mousewheel', this);
27844            this.wrapper.addEventListener('DOMMouseScroll', this);
27845        };
27846
27847        /*
27848        * Turns iScroll `mousewheel` option on dynamically
27849        * https://github.com/cubiq/iscroll/issues/1036
27850        */
27851        IScroll.prototype.wheelOff = function () {
27852            this.wrapper.removeEventListener('wheel', this);
27853            this.wrapper.removeEventListener('mousewheel', this);
27854            this.wrapper.removeEventListener('DOMMouseScroll', this);
27855        };
27856    }
27857
27858    /**
27859     * An object to handle overflow scrolling.
27860     * This uses jquery.slimScroll to accomplish overflow scrolling.
27861     * It is possible to pass in an alternate scrollOverflowHandler
27862     * to the fullpage.js option that implements the same functions
27863     * as this handler.
27864     *
27865     * @type {Object}
27866     */
27867    var iscrollHandler = {
27868        refreshId: null,
27869        iScrollInstances: [],
27870
27871        // Enables or disables the mouse wheel for the active section or all slides in it
27872        toggleWheel: function(value){
27873            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
27874            scrollable.each(function(){
27875                var iScrollInstance = $(this).data('iscrollInstance');
27876                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
27877                    if(value){
27878                        iScrollInstance.wheelOn();
27879                    }
27880                    else{
27881                        iScrollInstance.wheelOff();
27882                    }
27883                }
27884            });
27885        },
27886
27887        /**
27888        * Turns off iScroll for the destination section.
27889        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
27890        * scroll the destination section/slide before the sections animations ends.
27891        */
27892        onLeave: function(){
27893            iscrollHandler.toggleWheel(false);
27894        },
27895
27896        // Turns off iScroll for the leaving section
27897        beforeLeave: function(){
27898            iscrollHandler.onLeave()
27899        },
27900
27901        // Turns on iScroll on section load
27902        afterLoad: function(){
27903            iscrollHandler.toggleWheel(true);
27904        },
27905
27906        /**
27907         * Called when overflow scrolling is needed for a section.
27908         *
27909         * @param  {Object} element      jQuery object containing current section
27910         * @param  {Number} scrollHeight Current window height in pixels
27911         */
27912        create: function(element, scrollHeight) {
27913            var scrollable = element.find(SCROLLABLE_SEL);
27914
27915            scrollable.height(scrollHeight);
27916            scrollable.each(function() {
27917                var $this = $(this);
27918                var iScrollInstance = $this.data('iscrollInstance');
27919                if (iScrollInstance) {
27920                    $.each(iscrollHandler.iScrollInstances, function(){
27921                        $(this).destroy();
27922                    });
27923                }
27924
27925                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
27926                iscrollHandler.iScrollInstances.push(iScrollInstance);
27927
27928                //off by default until the section gets active
27929                iScrollInstance.wheelOff();
27930
27931                $this.data('iscrollInstance', iScrollInstance);
27932            });
27933        },
27934
27935        /**
27936         * Return a boolean depending on whether the scrollable element is a
27937         * the end or at the start of the scrolling depending on the given type.
27938         *
27939         * @param  {String}  type       Either 'top' or 'bottom'
27940         * @param  {Object}  scrollable jQuery object for the scrollable element
27941         * @return {Boolean}
27942         */
27943        isScrolled: function(type, scrollable) {
27944            var scroller = scrollable.data('iscrollInstance');
27945
27946            //no scroller?
27947            if (!scroller) {
27948                return true;
27949            }
27950
27951            if (type === 'top') {
27952                return scroller.y >= 0 && !scrollable.scrollTop();
27953            } else if (type === 'bottom') {
27954                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
27955            }
27956        },
27957
27958        /**
27959         * Returns the scrollable element for the given section.
27960         * If there are landscape slides, will only return a scrollable element
27961         * if it is in the active slide.
27962         *
27963         * @param  {Object}  activeSection jQuery object containing current section
27964         * @return {Boolean}
27965         */
27966        scrollable: function(activeSection){
27967            // if there are landscape slides, we check if the scrolling bar is in the current one or not
27968            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
27969                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
27970            }
27971            return activeSection.find(SCROLLABLE_SEL);
27972        },
27973
27974        /**
27975         * Returns the scroll height of the wrapped content.
27976         * If this is larger than the window height minus section padding,
27977         * overflow scrolling is needed.
27978         *
27979         * @param  {Object} element jQuery object containing current section
27980         * @return {Number}
27981         */
27982        scrollHeight: function(element) {
27983            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
27984        },
27985
27986        /**
27987         * Called when overflow scrolling is no longer needed for a section.
27988         *
27989         * @param  {Object} element      jQuery object containing current section
27990         */
27991        remove: function(element) {
27992            var scrollable = element.find(SCROLLABLE_SEL);
27993            if (scrollable.length) {
27994                var iScrollInstance = scrollable.data('iscrollInstance');
27995                iScrollInstance.destroy();
27996
27997                scrollable.data('iscrollInstance', null);
27998            }
27999            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
28000        },
28001
28002        /**
28003         * Called when overflow scrolling has already been setup but the
28004         * window height has potentially changed.
28005         *
28006         * @param  {Object}
28006 element      jQuery object containing current section
28007         * @param  {Number} scrollHeight Current window height in pixels
28008         */
28009        update: function(element, scrollHeight) {
28010            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
28011            //short period of time.
28012            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
28013            clearTimeout(iscrollHandler.refreshId);
28014            iscrollHandler.refreshId = setTimeout(function(){
28015                $.each(iscrollHandler.iScrollInstances, function(){
28016                    $(this).get(0).refresh();
28017                });
28018            }, 150);
28019
28020            //updating the wrappers height
28021            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
28022        },
28023
28024        /**
28025         * Called to get any additional elements needed to wrap the section
28026         * content in order to facilitate overflow scrolling.
28027         *
28028         * @return {String|Object} Can be a string containing HTML,
28029         *                         a DOM element, or jQuery object.
28030         */
28031        wrapContent: function() {
28032            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
28033        }
28034    };
28035});
28036
28037/* ========================================================================
28038 * Bootstrap: collapse.js v3.1.1
28039 * http://getbootstrap.com/javascript/#collapse
28040 * ========================================================================
28041 * Copyright 2011-2014 Twitter, Inc.
28042 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28043 * ======================================================================== */
28044
28045
28046+function ($) {
28047	'use strict';
28048
28049	// COLLAPSE PUBLIC CLASS DEFINITION
28050	// ================================
28051
28052	var Collapse = function (element, options) {
28053		this.$element      = $(element)
28054		this.options       = $.extend({}, Collapse.DEFAULTS, options)
28055		this.transitioning = null
28056
28057		if (this.options.parent) this.$parent = $(this.options.parent)
28058		if (this.options.toggle) this.toggle()
28059	}
28060
28061	Collapse.DEFAULTS = {
28062		toggle: true
28063	}
28064
28065	Collapse.prototype.dimension = function () {
28066		var hasWidth = this.$element.hasClass('width')
28067		return hasWidth ? 'width' : 'height'
28068	}
28069
28070	Collapse.prototype.show = function () {
28071		if (this.transitioning || this.$element.hasClass('in')) return
28072
28073		var startEvent = $.Event('show.bs.collapse')
28074		this.$element.trigger(startEvent)
28075		if (startEvent.isDefaultPrevented()) return
28076
28077		var actives = this.$parent && this.$parent.find('> .panel > .in')
28078
28079		if (actives && actives.length) {
28080			var hasData = actives.data('bs.collapse')
28081			if (hasData && hasData.transitioning) return
28082			actives.collapse('hide')
28083			hasData || actives.data('bs.collapse', null)
28084		}
28085
28086		var dimension = this.dimension()
28087
28088		this.$element
28089			.removeClass('collapse')
28090			.addClass('collapsing')[dimension](0)
28091
28092		this.transitioning = 1
28093
28094		var complete = function (e) {
28095			if (e && e.target != this.$element[0]) return
28096			this.$element
28097				.removeClass('collapsing')
28098				.addClass('collapse in')[dimension]('auto')
28099			this.transitioning = 0
28100			this.$element.trigger('shown.bs.collapse')
28101		}
28102
28103		if (!$.support.transition) return complete.call(this)
28104
28105		var scrollSize = $.camelCase(['scroll', dimension].join('-'))
28106
28107		this.$element
28108			.one($.support.transition.end, $.proxy(complete, this))
28109			.emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
28110	}
28111
28112	Collapse.prototype.hide = function () {
28113		if (this.transitioning || !this.$element.hasClass('in')) return
28114
28115		var startEvent = $.Event('hide.bs.collapse')
28116		this.$element.trigger(startEvent)
28117		if (startEvent.isDefaultPrevented()) return
28118
28119		var dimension = this.dimension()
28120
28121		this.$element[dimension](this.$element[dimension]())[0].offsetHeight
28122
28123		this.$element
28124			.addClass('collapsing')
28125			.removeClass('collapse')
28126			.removeClass('in')
28127
28128		this.transitioning = 1
28129
28130		var complete = function (e) {
28131			if (e && e.target != this.$element[0]) return
28132			this.transitioning = 0
28133			this.$element
28134				.trigger('hidden.bs.collapse')
28135				.removeClass('collapsing')
28136				.addClass('collapse')
28137		}
28138
28139		if (!$.support.transition) return complete.call(this)
28140
28141		this.$element
28142			[dimension](0)
28143			.one($.support.transition.end, $.proxy(complete, this))
28144			.emulateTransitionEnd(350)
28145	}
28146
28147	Collapse.prototype.toggle = function () {
28148		this[this.$element.hasClass('in') ? 'hide' : 'show']()
28149	}
28150
28151
28152	// COLLAPSE PLUGIN DEFINITION
28153	// ==========================
28154
28155	var old = $.fn.collapse
28156
28157	$.fn.collapse = function (option) {
28158		return this.each(function () {
28159			var $this   = $(this)
28160			var data    = $this.data('bs.collapse')
28161			var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
28162
28163			if (!data && options.toggle && option == 'show') option = !option
28164			if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
28165			if (typeof option == 'string') data[option]()
28166		})
28167	}
28168
28169	$.fn.collapse.Constructor = Collapse
28170
28171
28172	// COLLAPSE NO CONFLICT
28173	// ====================
28174
28175	$.fn.collapse.noConflict = function () {
28176		$.fn.collapse = old
28177		return this
28178	}
28179
28180
28181	// COLLAPSE DATA-API
28182	// =================
28183
28184	$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
28185		var $this   = $(this), href
28186		var target  = $this.attr('data-target')
28187				|| e.preventDefault()
28188				|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
28189		//Edited by Uncode to replace ID in panel [START]
28190		var _target = href.replace(/^#/, "");
28191		if ( $('[data-id="' + _target + '"]').length ) {
28192			var $target = $('[data-id="' + _target + '"]')
28193		} else {
28194			var $target = $(target)
28195		}
28196		//Edited by Uncode to replace ID in panel [END]
28197		var data    = $target.data('bs.collapse')
28198		var option  = data ? 'toggle' : $this.data()
28199		var parent  = $this.attr('data-parent')
28200		var $parent = parent && $(parent)
28201
28202		if (!data || !data.transitioning) {
28203			if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
28204			$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
28205		}
28206
28207		$target.collapse(option)
28208	})
28209
28210}(jQuery);
28211
28212/* ========================================================================
28213 * Bootstrap: tab.js v3.1.1
28214 * http://getbootstrap.com/javascript/#tabs
28215 * ========================================================================
28216 * Copyright 2011-2014 Twitter, Inc.
28217 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28218 * ======================================================================== */
28219
28220
28221+function ($) {
28222  'use strict';
28223
28224  // TAB CLASS DEFINITION
28225  // ====================
28226
28227  var Tab = function (element) {
28228    this.element = $(element)
28229  }
28230
28231  Tab.prototype.show = function () {
28232    var $this    = this.element
28233    var $ul      = $this.closest('ul:not(.dropdown-menu)')
28234    var selector = $this.data('target')
28235
28236    if (!selector) {
28237      selector = $this.attr('href')
28238      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
28239    }
28240
28241    if ($this.parent('li').hasClass('active')) return
28242
28243    var previous = $ul.find('.active:last a')[0]
28244    var e        = $.Event('show.bs.tab', {
28245      relatedTarget: previous
28246    })
28247
28248    $this.trigger(e)
28249
28250    if (e.isDefaultPrevented()) return
28251
28252    //Edited by Uncode to replace ID in panel [START]
28253    var _target = selector.replace(/^#/, "");
28254    if ( $('[data-id="' + _target + '"]').length )
28255      var $target = $('[data-id="' + _target + '"]')
28256    else
28257      var $target = $(selector)
28258    //Edited by Uncode to replace ID in panel [END]
28259
28260    this.activate($this.parent('li'), $ul)
28261    this.activate($target, $target.parent(), function () {
28262      $this.trigger({
28263        type: 'shown.bs.tab',
28264        relatedTarget: previous
28265      })
28266    })
28267  }
28268
28269  Tab.prototype.activate = function (element, container, callback) {
28270    var $active    = container.find('> .active')
28271    var transition = callback
28272      && $.support.transition
28273      && $active.hasClass('fade')
28274
28275    function next() {
28276      $active
28277        .removeClass('active')
28278        .find('> .dropdown-menu > .active')
28279        .removeClass('active')
28280
28281      element.addClass('active')
28282
28283      if (transition) {
28284        element[0].offsetWidth // reflow for transition
28285        element.addClass('in')
28286      } else {
28287        element.removeClass('fade')
28288      }
28289
28290      if (element.parent('.dropdown-menu')) {
28291        element.closest('li.dropdown').addClass('active')
28292      }
28293
28294      callback && callback()
28295    }
28296
28297    transition ?
28298      $active
28299        .one($.support.transition.end, next)
28300        .emulateTransitionEnd(150) :
28301      next()
28302
28303    $active.removeClass('in')
28304  }
28305
28306
28307  // TAB PLUGIN DEFINITION
28308  // =====================
28309
28310  var old = $.fn.tab
28311
28312  $.fn.tab = function ( option ) {
28313    return this.each(function () {
28314      var $this = $(this)
28315      var data  = $this.data('bs.tab')
28316
28317      if (!data) $this.data('bs.tab', (data = new Tab(this)))
28318      if (typeof option == 'string') data[option]()
28319    })
28320  }
28321
28322  $.fn.tab.Constructor = Tab
28323
28324
28325  // TAB NO CONFLICT
28326  // ===============
28327
28328  $.fn.tab.noConflict = function () {
28329    $.fn.tab = old
28330    return this
28331  }
28332
28333
28334  // TAB DATA-API
28335  // ============
28336
28337  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
28338    e.preventDefault()
28339    $(this).tab('show')
28340  })
28341
28342}(jQuery);
28343
28344/* ========================================================================
28345 * Bootstrap: tooltip.js v3.1.1
28346 * http://getbootstrap.com/javascript/#tooltip
28347 * Inspired by the original jQuery.tipsy by Jason Frame
28348 * ========================================================================
28349 * Copyright 2011-2014 Twitter, Inc.
28350 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28351 * ======================================================================== */
28352
28353
28354+function ($) {
28355  'use strict';
28356
28357  // TOOLTIP PUBLIC CLASS DEFINITION
28358  // ===============================
28359
28360  var Tooltip = function (element, options) {
28361    this.type       =
28362    this.options    =
28363    this.enabled    =
28364    this.timeout    =
28365    this.hoverState =
28366    this.$element   = null
28367
28368    this.init('tooltip', element, options)
28369  }
28370
28371  Tooltip.DEFAULTS = {
28372    animation: true,
28373    placement: 'top',
28374    selector: false,
28375    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
28376    trigger: 'hover focus',
28377    title: '',
28378    delay: 0,
28379    html: false,
28380    container: false,
28381    viewport: {
28382      selector: 'body',
28383      padding: 0
28384    }
28385  }
28386
28387  Tooltip.prototype.init = function (type, element, options) {
28388    this.enabled   = true
28389    this.type      = type
28390    this.$element  = $(element)
28391    this.options   = this.getOptions(options)
28392    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
28393
28394    var triggers = this.options.trigger.split(' ')
28395
28396    for (var i = triggers.length; i--;) {
28397      var trigger = triggers[i]
28398
28399      if (trigger == 'click') {
28400        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
28401      } else if (trigger != 'manual') {
28402        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
28403        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
28404
28405        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
28406        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
28407      }
28408    }
28409
28410    this.options.selector ?
28411      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
28412      this.fixTitle()
28413  }
28414
28415  Tooltip.prototype.getDefaults = function () {
28416    return Tooltip.DEFAULTS
28417  }
28418
28419  Tooltip.prototype.getOptions = function (options) {
28420    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
28421
28422    if (options.delay && typeof options.delay == 'number') {
28423      options.delay = {
28424        show: options.delay,
28425        hide: options.delay
28426      }
28427    }
28428
28429    return options
28430  }
28431
28432  Tooltip.prototype.getDelegateOptions = function () {
28433    var options  = {}
28434    var defaults = this.getDefaults()
28435
28436    this._options && $.each(this._options, function (key, value) {
28437      if (defaults[key] != value) options[key] = value
28438    })
28439
28440    return options
28441  }
28442
28443  Tooltip.prototype.enter = function (obj) {
28444    var self = obj instanceof this.constructor ?
28445      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
28446
28447    clearTimeout(self.timeout)
28448
28449    self.hoverState = 'in'
28450
28451    if (!self.options.delay || !self.options.delay.show) return self.show()
28452
28453    self.timeout = setTimeout(function () {
28454      if (self.hoverState == 'in') self.show()
28455    }, self.options.delay.show)
28456  }
28457
28458  Tooltip.prototype.leave = function (obj) {
28459    var self = obj instanceof this.constructor ?
28460      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
28461
28462    clearTimeout(self.timeout)
28463
28464    self.hoverState = 'out'
28465
28466    if (!self.options.delay || !self.options.delay.hide) return self.hide()
28467
28468    self.timeout = setTimeout(function () {
28469      if (self.hoverState == 'out') self.hide()
28470    }, self.options.delay.hide)
28471  }
28472
28473  Tooltip.prototype.show = function () {
28474    var e = $.Event('show.bs.' + this.type)
28475
28476    if (this.hasContent() && this.enabled) {
28477      this.$element.trigger(e)
28478
28479      if (e.isDefaultPrevented()) return
28480      var that = this;
28481
28482      var $tip = this.tip()
28483
28484      this.setContent()
28485
28486      if (this.options.animation) $tip.addClass('fade')
28487
28488      var placement = typeof this.options.placement == 'function' ?
28489        this.options.placement.call(this, $tip[0], this.$element[0]) :
28490        this.options.placement
28491
28492      var autoToken = /\s?auto?\s?/i
28493      var autoPlace = autoToken.test(placement)
28494      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
28495
28496      $tip
28497        .detach()
28498        .css({ top: 0, left: 0, display: 'block' })
28499        .addClass(placement)
28500
28501      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
28502
28503      var pos          = this.getPosition()
28504      var actualWidth  = $tip[0].offsetWidth
28505      var actualHeight = $tip[0].offsetHeight
28506
28507      if (autoPlace) {
28508        var orgPlacement = placement
28509        var $parent      = this.$element.parent()
28510        var parentDim    = this.getPosition($parent)
28511
28512        placement = placement == 'bottom' && pos.top   + pos.height       + actualHeight - parentDim.scroll > parentDim.height ? 'top'    :
28513                    placement == 'top'    && pos.top   - parentDim.scroll - actualHeight < 0                                   ? 'bottom' :
28514                    placement == 'right'  && pos.right + actualWidth      > parentDim.width                                    ? 'left'   :
28515                    placement == 'left'   && pos.left  - actualWidth      < parentDim.left                                     ? 'right'  :
28516                    placement
28517
28518        $tip
28519          .removeClass(orgPlacement)
28520          .addClass(placement)
28521      }
28522
28523      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
28524
28525      this.applyPlacement(calculatedOffset, placement)
28526      this.hoverState = null
28527
28528      var complete = function() {
28529        that.$element.trigger('shown.bs.' + that.type)
28530      }
28531
28532      $.support.transition && this.$tip.hasClass('fade') ?
28533        $tip
28534          .one($.support.transition.end, complete)
28535          .emulateTransitionEnd(150) :
28536        complete()
28537    }
28538  }
28539
28540  Tooltip.prototype.applyPlacement = function (offset, placement) {
28541    var $tip   = this.tip()
28542    var width  = $tip[0].offsetWidth
28543    var height = $tip[0].offsetHeight
28544
28545    // manually read margins because getBoundingClientRect includes difference
28546    var marginTop = parseInt($tip.css('margin-top'), 10)
28547    var marginLeft = parseInt($tip.css('margin-left'), 10)
28548
28549    // we must check for NaN for ie 8/9
28550    if (isNaN(marginTop))  marginTop  = 0
28551    if (isNaN(marginLeft)) marginLeft = 0
28552
28553    offset.top  = offset.top  + marginTop
28554    offset.left = offset.left + marginLeft
28555
28556    // $.fn.offset doesn't round pixel values
28557    // so we use setOff
28557set directly with our own function B-0
28558    $.offset.setOffset($tip[0], $.extend({
28559      using: function (props) {
28560        $tip.css({
28561          top: Math.round(props.top),
28562          left: Math.round(props.left)
28563        })
28564      }
28565    }, offset), 0)
28566
28567    $tip.addClass('in')
28568
28569    // check to see if placing tip in new offset caused the tip to resize itself
28570    var actualWidth  = $tip[0].offsetWidth
28571    var actualHeight = $tip[0].offsetHeight
28572
28573    if (placement == 'top' && actualHeight != height) {
28574      offset.top = offset.top + height - actualHeight
28575    }
28576
28577    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
28578
28579    if (delta.left) offset.left += delta.left
28580    else offset.top += delta.top
28581
28582    var arrowDelta          = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
28583    var arrowPosition       = delta.left ? 'left'        : 'top'
28584    var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
28585
28586    $tip.offset(offset)
28587    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
28588  }
28589
28590  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
28591    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
28592  }
28593
28594  Tooltip.prototype.setContent = function () {
28595    var $tip  = this.tip()
28596    var title = this.getTitle()
28597
28598    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
28599    $tip.removeClass('fade in top bottom left right')
28600  }
28601
28602  Tooltip.prototype.hide = function () {
28603    var that = this
28604    var $tip = this.tip()
28605    var e    = $.Event('hide.bs.' + this.type)
28606
28607    function complete() {
28608      if (that.hoverState != 'in') $tip.detach()
28609      that.$element.trigger('hidden.bs.' + that.type)
28610    }
28611
28612    this.$element.trigger(e)
28613
28614    if (e.isDefaultPrevented()) return
28615
28616    $tip.removeClass('in')
28617
28618    $.support.transition && this.$tip.hasClass('fade') ?
28619      $tip
28620        .one($.support.transition.end, complete)
28621        .emulateTransitionEnd(150) :
28622      complete()
28623
28624    this.hoverState = null
28625
28626    return this
28627  }
28628
28629  Tooltip.prototype.fixTitle = function () {
28630    var $e = this.$element
28631    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
28632      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
28633    }
28634  }
28635
28636  Tooltip.prototype.hasContent = function () {
28637    return this.getTitle()
28638  }
28639
28640  Tooltip.prototype.getPosition = function ($element) {
28641    $element   = $element || this.$element
28642    var el     = $element[0]
28643    var isBody = el.tagName == 'BODY'
28644    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
28645      scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
28646      width:  isBody ? $(window).width()  : $element.outerWidth(),
28647      height: isBody ? $(window).height() : $element.outerHeight()
28648    }, isBody ? {top: 0, left: 0} : $element.offset())
28649  }
28650
28651  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
28652    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
28653           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
28654           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
28655        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
28656
28657  }
28658
28659  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
28660    var delta = { top: 0, left: 0 }
28661    if (!this.$viewport) return delta
28662
28663    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
28664    var viewportDimensions = this.getPosition(this.$viewport)
28665
28666    if (/right|left/.test(placement)) {
28667      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
28668      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
28669      if (topEdgeOffset < viewportDimensions.top) { // top overflow
28670        delta.top = viewportDimensions.top - topEdgeOffset
28671      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
28672        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
28672EdgeOffset
28673      }
28674    } else {
28675      var leftEdgeOffset  = pos.left - viewportPadding
28676      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
28677      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
28678        delta.left = viewportDimensions.left - leftEdgeOffset
28679      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
28680        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
28681      }
28682    }
28683
28684    return delta
28685  }
28686
28687  Tooltip.prototype.getTitle = function () {
28688    var title
28689    var $e = this.$element
28690    var o  = this.options
28691
28692    title = $e.attr('data-original-title')
28693      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
28694
28695    return title
28696  }
28697
28698  Tooltip.prototype.tip = function () {
28699    return this.$tip = this.$tip || $(this.options.template)
28700  }
28701
28702  Tooltip.prototype.arrow = function () {
28703    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
28704  }
28705
28706  Tooltip.prototype.validate = function () {
28707    if (!this.$element[0].parentNode) {
28708      this.hide()
28709      this.$element = null
28710      this.options  = null
28711    }
28712  }
28713
28714  Tooltip.prototype.enable = function () {
28715    this.enabled = true
28716  }
28717
28718  Tooltip.prototype.disable = function () {
28719    this.enabled = false
28720  }
28721
28722  Tooltip.prototype.toggleEnabled = function () {
28723    this.enabled = !this.enabled
28724  }
28725
28726  Tooltip.prototype.toggle = function (e) {
28727    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
28728    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
28729  }
28730
28731  Tooltip.prototype.destroy = function () {
28732    clearTimeout(this.timeout)
28733    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
28734  }
28735
28736
28737  // TOOLTIP PLUGIN DEFINITION
28738  // =========================
28739
28740  var old = $.fn.tooltip
28741
28742  $.fn.tooltip = function (option) {
28743    return this.each(function () {
28744      var $this   = $(this)
28745      var data    = $this.data('bs.tooltip')
28746      var options = typeof option == 'object' && option
28747
28748      if (!data && option == 'destroy') return
28749      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
28750      if (typeof option == 'string') data[option]()
28751    })
28752  }
28753
28754  $.fn.tooltip.Constructor = Tooltip
28755
28756
28757  // TOOLTIP NO CONFLICT
28758  // ===================
28759
28760  $.fn.tooltip.noConflict = function () {
28761    $.fn.tooltip = old
28762    return this
28763  }
28764
28765}(jQuery);
28766
28767/* ========================================================================
28768 * Bootstrap: transition.js v3.1.1
28769 * http://getbootstrap.com/javascript/#transitions
28770 * ========================================================================
28771 * Copyright 2011-2014 Twitter, Inc.
28772 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
28773 * ======================================================================== */
28774
28775
28776+function ($) {
28777  'use strict';
28778
28779  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
28780  // ============================================================
28781
28782  function transitionEnd() {
28783    var el = document.createElement('bootstrap')
28784
28785    var transEndEventNames = {
28786      WebkitTransition : 'webkitTransitionEnd',
28787      MozTransition    : 'transitionend',
28788      OTransition      : 'oTransitionEnd otransitionend',
28789      transition       : 'transitionend'
28790    }
28791
28792    for (var name in transEndEventNames) {
28793      if (el.style[name] !== undefined) {
28794        return { end: transEndEventNames[name] }
28795      }
28796    }
28797
28798    return false // explicit for ie8 (  ._.)
28799  }
28800
28801  // http://blog.alexmaccaw.com/css-transitions
28802  $.fn.emulateTransitionEnd = function (duration) {
28803    var called = false, $el = this
28804    $(this).one($.support.transition.end, function () { called = true })
28805    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
28806    setTimeout(callback, duration)
28807    return this
28808  }
28809
28810  $(function () {
28811    $.support.transition = transitionEnd()
28812  })
28813
28814}(jQuery);
28815
28816
28817// ------------------------------------------
28818// Rellax.js
28819// Buttery smooth parallax library
28820// Copyright (c) 2016 Moe Amaya (@moeamaya)
28821// MIT license
28822//
28823// Thanks to Paraxify.js and Jaime Cabllero
28824// for parallax concepts
28825// ------------------------------------------
28826
28827(function (root, factory) {
28828	if (typeof define === 'function' && define.amd) {
28829		// AMD. Register as an anonymous module.
28830		define([], factory);
28831	} else if (typeof module === 'object' && module.exports) {
28832		// Node. Does not work with strict CommonJS, but
28833		// only CommonJS-like environments that support module.exports,
28834		// like Node.
28835		module.exports = factory();
28836	} else {
28837		// Browser globals (root is window)
28838		root.Rellax = factory();
28839	}
28840}(typeof window !== "undefined" ? window : global, function () {
28841	var Rellax = function(el, options){
28842		"use strict";
28843
28844		var self = Object.create(Rellax.prototype);
28845
28846		var posY = 0;
28847		var screenY = 0;
28848		var posX = 0;
28849		var screenX = 0;
28850		var blocks = [];
28851		var pause = true;
28852
28853		// check what requestAnimationFrame to use, and if
28854		// it's not supported, use the onscroll event
28855		var loop = window.requestAnimationFrame ||
28856			window.webkitRequestAnimationFrame ||
28857			window.mozRequestAnimationFrame ||
28858			window.msRequestAnimationFrame ||
28859			window.oRequestAnimationFrame ||
28860			function(callback){ return setTimeout(callback, 1000 / 60); };
28861
28862		// store the id for later use
28863		var loopId = null;
28864
28865		// Test via a getter in the options object to see if the passive property is accessed
28866		var supportsPassive = false;
vendor: 10,724 bytes, lines 28867-29168
28867		try {
28868			var opts = Object.defineProperty({}, 'passive', {
28869				get: function() {
28870					supportsPassive = true;
28871				}
28872			});
28873			window.addEventListener("testPassive", null, opts);
28874			window.removeEventListener("testPassive", null, opts);
28875		} catch (e) {}
28876
28877		// check what cancelAnimation method to use
28878		var clearLoop = window.cancelAnimationFrame || window.mozCancelAnimationFrame || clearTimeout;
28879
28880		// check which transform property to use
28881		var transformProp = window.transformProp || (function(){
28882				var testEl = document.createElement('div');
28883				if (testEl.style.transform === null) {
28884					var vendors = ['Webkit', 'Moz', 'ms'];
28885					for (var vendor in vendors) {
28886						if (testEl.style[ vendors[vendor] + 'Transform' ] !== undefined) {
28887							return vendors[vendor] + 'Transform';
28888						}
28889					}
28890				}
28891				return 'transform';
28892			})();
28893
28894		// Default Settings
28895		self.options = {
28896			speed: -2,
28897			verticalSpeed: null,
28898			horizontalSpeed: null,
28899			breakpoints: [576, 768, 1201],
28900			center: false,
28901			wrapper: null,
28902			relativeToWrapper: false,
28903			round: true,
28904			vertical: true,
28905			horizontal: false,
28906			verticalScrollAxis: "y",
28907			horizontalScrollAxis: "x",
28908			callback: function() {},
28909		};
28910
28911		// User defined options (might have more in the future)
28912		if (options){
28913			Object.keys(options).forEach(function(key){
28914				self.options[key] = options[key];
28915			});
28916		}
28917
28918		function validateCustomBreakpoints () {
28919			if (self.options.breakpoints.length === 3 && Array.isArray(self.options.breakpoints)) {
28920				var isAscending = true;
28921				var isNumerical = true;
28922				var lastVal;
28923				self.options.breakpoints.forEach(function (i) {
28924					if (typeof i !== 'number') isNumerical = false;
28925					if (lastVal !== null) {
28926						if (i < lastVal) isAscending = false;
28927					}
28928					lastVal = i;
28929				});
28930				if (isAscending && isNumerical) return;
28931			}
28932			// revert defaults if set incorrectly
28933			self.options.breakpoints = [576, 768, 1201];
28934			console.warn("Rellax: You must pass an array of 3 numbers in ascending order to the breakpoints option. Defaults reverted");
28935		}
28936
28937		if (options && options.breakpoints) {
28938			validateCustomBreakpoints();
28939		}
28940
28941		// By default, rellax class
28942		if (!el) {
28943			el = '.rellax';
28944		}
28945
28946		// check if el is a className or a node
28947		var elements = typeof el === 'string' ? document.querySelectorAll(el) : [el];
28948
28949		// Now query selector
28950		if (elements.length > 0) {
28951			self.elems = elements;
28952		}
28953
28954		// The elements don't exist
28955		else {
28956			console.warn("Rellax: The elements you're trying to select don't exist.");
28957			return;
28958		}
28959
28960		// Has a wrapper and it exists
28961		if (self.options.wrapper) {
28962			if (!self.options.wrapper.nodeType) {
28963				var wrapper = document.querySelector(self.options.wrapper);
28964
28965				if (wrapper) {
28966					self.options.wrapper = wrapper;
28967				} else {
28968					console.warn("Rellax: The wrapper you're trying to use doesn't exist.");
28969					return;
28970				}
28971			}
28972		}
28973
28974		// set a placeholder for the current breakpoint
28975		var currentBreakpoint;
28976
28977		// helper to determine current breakpoint
28978		var getCurrentBreakpoint = function (w) {
28979			var bp = self.options.breakpoints;
28980			if (w < bp[0]) return 'xs';
28981			if (w >= bp[0] && w < bp[1]) return 'sm';
28982			if (w >= bp[1] && w < bp[2]) return 'md';
28983			return 'lg';
28984		};
28985
28986		// Get and cache initial position of all elements
28987		var cacheBlocks = function() {
28988			for (var i = 0; i < self.elems.length; i++){
28989				var block = createBlock(self.elems[i]);
28990				blocks.push(block);
28991			}
28992		};
28993
28994
28995		// Let's kick this script off
28996		// Build array for cached element values
28997		var init = function() {
28998			for (var i = 0; i < blocks.length; i++){
28999				self.elems[i].style.cssText = blocks[i].style;
29000			}
29001
29002			blocks = [];
29003
29004			screenY = window.innerHeight;
29005			screenX = window.innerWidth;
29006			currentBreakpoint = getCurrentBreakpoint(screenX);
29007
29008			setPosition();
29009
29010			cacheBlocks();
29011
29012			animate();
29013
29014			// If paused, unpause and set listener for window resizing events
29015			if (pause) {
29016				window.addEventListener('resize', init);
29017				pause = false;
29018				// Start the loop
29019				update();
29020			}
29021		};
29022
29023		// We want to cache the parallax blocks'
29024		// values: base, top, height, speed
29025		// el: is dom object, return: el cache values
29026		var createBlock = function(el) {
29027			var dataPercentage = el.getAttribute( 'data-rellax-percentage' );
29028			var dataSpeed = el.getAttribute( 'data-rellax-speed' );
29029			var dataXsSpeed = el.getAttribute( 'data-rellax-xs-speed' );
29030			var dataMobileSpeed = el.getAttribute( 'data-rellax-mobile-speed' );
29031			var dataTabletSpeed = el.getAttribute( 'data-rellax-tablet-speed' );
29032			var dataDesktopSpeed = el.getAttribute( 'data-rellax-desktop-speed' );
29033			var dataVerticalSpeed = el.getAttribute('data-rellax-vertical-speed');
29034			var dataHorizontalSpeed = el.getAttribute('data-rellax-horizontal-speed');
29035			var dataVericalScrollAxis = el.getAttribute('data-rellax-vertical-scroll-axis');
29036			var dataHorizontalScrollAxis = el.getAttribute('data-rellax-horizontal-scroll-axis');
29037			var dataZindex = el.getAttribute( 'data-rellax-zindex' ) || 0;
29038			var dataMin = el.getAttribute( 'data-rellax-min' );
29039			var dataMax = el.getAttribute( 'data-rellax-max' );
29040			var dataMinX = el.getAttribute('data-rellax-min-x');
29041			var dataMaxX = el.getAttribute('data-rellax-max-x');
29042			var dataMinY = el.getAttribute('data-rellax-min-y');
29043			var dataMaxY = el.getAttribute('data-rellax-max-y');
29044			var mapBreakpoints;
29045			var breakpoints = true;
29046
29047			if (!dataXsSpeed && !dataMobileSpeed && !dataTabletSpeed && !dataDesktopSpeed) {
29048				breakpoints = false;
29049			} else {
29050				mapBreakpoints = {
29051					'xs': dataXsSpeed,
29052					'sm': dataMobileSpeed,
29053					'md': dataTabletSpeed,
29054					'lg': dataDesktopSpeed
29055				};
29056			}
29057
29058			// initializing at scrollY = 0 (top of browser), scrollX = 0 (left of browser)
29059			// ensures elements are positioned based on HTML layout.
29060			//
29061			// If the element has the percentage attribute, the posY and posX needs to be
29062			// the current scroll position's value, so that the elements are still positioned based on HTML layout
29063			var wrapperPosY = self.options.wrapper ? self.options.wrapper.scrollTop : (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
29064			// If the option relativeToWrapper is true, use the wrappers offset to top, subtracted from the current page scroll.
29065			if (self.options.relativeToWrapper) {
29066				var scrollPosY = (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
29067				wrapperPosY = scrollPosY - self.options.wrapper.offsetTop;
29068			}
29069			var posY = self.options.vertical ? ( dataPercentage || self.options.center ? wrapperPosY : 0 ) : 0;
29070			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;
29071
29072			var blockTop = posY + el.getBoundingClientRect().top;
29073			var blockHeight = el.clientHeight || el.offsetHeight || el.scrollHeight;
29074
29075			var blockLeft = posX + el.getBoundingClientRect().left;
29076			var blockWidth = el.clientWidth || el.offsetWidth || el.scrollWidth;
29077
29078			// apparently parallax equation everyone uses
29079			var percentageY = dataPercentage ? dataPercentage : (posY - blockTop + screenY) / (blockHeight + screenY);
29080			var percentageX = dataPercentage ? dataPercentage : (posX - blockLeft + screenX) / (blockWidth + screenX);
29081			if(self.options.center){ percentageX = 0.5; percentageY = 0.5; }
29082
29083			// Optional individual block speed as data attr, otherwise global speed
29084			var speed = (breakpoints && mapBreakpoints[currentBreakpoint] !== null) ? Number(mapBreakpoints[currentBreakpoint]) : (dataSpeed ? dataSpeed : self.options.speed);
29085			var verticalSpeed = dataVerticalSpeed ? dataVerticalSpeed : self.options.verticalSpeed;
29086			var horizontalSpeed = dataHorizontalSpeed ? dataHorizontalSpeed : self.options.horizontalSpeed;
29087
29088			// Optional individual block movement axis direction as data attr, otherwise global movement direction
29089			var verticalScrollAxis = dataVericalScrollAxis ? dataVericalScrollAxis : self.options.verticalScrollAxis;
29090			var horizontalScrollAxis = dataHorizontalScrollAxis ? dataHorizontalScrollAxis : self.options.horizontalScrollAxis;
29091
29092			var bases = updatePosition(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed);
29093
29094			// ~~Store non-translate3d transforms~~
29095			// Store inline styles and extract transforms
29096			var style = el.style.cssText;
29097			var transform = '';
29098
29099			// Check if there's an inline styled transform
29100			var searchResult = /transform\s*:/i.exec(style);
29101			if (searchResult) {
29102				// Get the index of the transform
29103				var index = searchResult.index;
29104
29105				// Trim the style to the transform point and get the following semi-colon index
29106				var trimmedStyle = style.slice(index);
29107				var delimiter = trimmedStyle.indexOf(';');
29108
29109				// Remove "transform" string and save the attribute
29110				if (delimiter) {
29111					transform = " " + trimmedStyle.slice(11, delimiter).replace(/\s/g,'');
29112				} else {
29113					transform = " " + trimmedStyle.slice(11).replace(/\s/g,'');
29114				}
29115			}
29116
29117			return {
29118				baseX: bases.x,
29119				baseY: bases.y,
29120				top: blockTop,
29121				left: blockLeft,
29122				height: blockHeight,
29123				width: blockWidth,
29124				speed: speed,
29125				verticalSpeed: verticalSpeed,
29126				horizontalSpeed: horizontalSpeed,
29127				verticalScrollAxis: verticalScrollAxis,
29128				horizontalScrollAxis: horizontalScrollAxis,
29129				style: style,
29130				transform: transform,
29131				zindex: dataZindex,
29132				min: dataMin,
29133				max: dataMax,
29134				minX: dataMinX,
29135				maxX: dataMaxX,
29136				minY: dataMinY,
29137				maxY: dataMaxY
29138			};
29139		};
29140
29141		// set scroll position (posY, posX)
29142		// side effect method is not ideal, but okay for now
29143		// returns true if the scroll changed, false if nothing happened
29144		var setPosition = function() {
29145			var oldY = posY;
29146			var oldX = posX;
29147
29148			posY = self.options.wrapper ? self.options.wrapper.scrollTop : (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
29149			posX = self.options.wrapper ? self.options.wrapper.scrollLeft : (document.documentElement || document.body.parentNode || document.body).scrollLeft || window.pageXOffset;
29150			// If option relativeToWrapper is true, use relative wrapper value instead.
29151			if (self.options.relativeToWrapper) {
29152				var scrollPosY = (document.documentElement || document.body.parentNode || document.body).scrollTop || window.pageYOffset;
29153				posY = scrollPosY - self.options.wrapper.offsetTop;
29154			}
29155
29156
29157			if (oldY != posY && self.options.vertical) {
29158				// scroll changed, return true
29159				return true;
29160			}
29161
29162			if (oldX != posX && self.options.horizontal) {
29163				// scroll changed, return true
29164				return true;
29165			}
29166
29167			// scroll did not change
29168			return false;
29169		};
29170
29171		// Ahh a pure function, gets new transform value
29172		// based on scrollPosition and speed
29173		// Allow for decimal pixel values
29174		var updatePosition = function(percentageX, percentageY, speed, verticalSpeed, horizontalSpeed) {
29175			var result = {};
29176			var valueX = ((horizontalSpeed ? horizontalSpeed : speed) * (100 * (1 - percentageX)));
29177			var valueY = ((verticalSpeed ? verticalSpeed : speed) * (100 * (1 - percentageY)));
29178
29179			result.x = self.options.round ? Math.round(valueX) : Math.round(valueX * 100) / 100;
29180			result.y = self.options.round ? Math.round(valueY) : Math.round(valueY * 100) / 100;
29181
29182			return result;
29183		};
29184
29185		// Remove event listeners and loop again
29186		var deferredUpdate = function() {
29187			window.removeEventListener('resize', deferredUpdate);
29188			window.removeEventListener('orientationchange', deferredUpdate);
29189			(self.options.wrapper ? self.options.wrapper : window).removeEventListener('scroll', deferredUpdate);
29190			(self.options.wrapper ? self.options.wrapper : document).removeEventListener('touchmove', deferredUpdate);
29191
29192			// loop again
29193			loopId = loop(update);
29194		};
29195
29196		// Loop
29197		var update = function() {
29198			if (setPosition() && pause === false) {
29199				animate();
29200
29201				// loop again
29202				loopId = loop(update);
29203			} else {
29204				loopId = null;
29205
29206				// Don't animate until we get a position updating event
29207				window.addEventListener('resize', deferredUpdate);
29208				window.addEventListener('orientationchange', deferredUpdate);
29209				(self.options.wrapper ? self.options.wrapper : window).addEventListener('scroll', deferredUpdate, supportsPassive ? { passive: true } : false);
29210				(self.options.wrapper ? self.options.wrapper : document).addEventListener('touchmove', deferredUpdate, supportsPassive ? { passive: true } : false);
29211			}
29212		};
29213
29214		// Transform3d on parallax element
29215		var animate = function() {
29216			var positions;
29217			for (var i = 0; i < self.elems.length; i++){
29218				// Determine relevant movement directions
29219				var verticalScrollAxis = blocks[i].verticalScrollAxis.toLowerCase();
29220				var horizontalScrollAxis = blocks[i].horizontalScrollAxis.toLowerCase();
29221				var verticalScrollX = verticalScrollAxis.indexOf("x") != -1 ? posY : 0;
29222				var verticalScrollY = verticalScrollAxis.indexOf("y") != -1 ? posY : 0;
29223				var horizontalScrollX = horizontalScrollAxis.indexOf("x") != -1 ? posX : 0;
29224				var horizontalScrollY = horizontalScrollAxis.indexOf("y") != -1 ? posX : 0;
29225
29226				var percentageY = ((verticalScrollY + horizontalScrollY - blocks[i].top + screenY) / (blocks[i].height + screenY));
29227				var percentageX = ((verticalScrollX + horizontalScrollX - blocks[i].left + screenX) / (blocks[i].width + screenX));
29228
29229				// Subtracting initialize value, so element stays in same spot as HTML
29230				positions = updatePosition(percentageX, percentageY, blocks[i].speed, blocks[i].verticalSpeed, blocks[i].horizontalSpeed);
29231				var positionY = positions.y - blocks[i].baseY;
29232				var positionX = positions.x - blocks[i].baseX;
29233
29234				// The next two "if" blocks go like this:
29235				// Check if a limit is defined (first "min", then "max");
29236				// Check if we need to change the Y or the X
29237				// (Currently working only if just one of the axes is enabled)
29238				// Then, check if the new position is inside the allowed limit
29239				// If so, use new position. If not, set position to limit.
29240
29241				// Check if a min limit is defined
29242				if (blocks[i].min !== null) {
29243					if (self.options.vertical && !self.options.horizontal) {
29244						positionY = positionY <= blocks[i].min ? blocks[i].min : positionY;
29245					}
29246					if (self.options.horizontal && !self.options.vertical) {
29247						positionX = positionX <= blocks[i].min ? blocks[i].min : positionX;
29248					}
29249				}
29250
29251				// Check if directional min limits are defined
29252				if (blocks[i].minY != null) {
29253						positionY = positionY <= blocks[i].minY ? blocks[i].minY : positionY;
29254				}
29255				if (blocks[i].minX != null) {
29256						positionX = positionX <= blocks[i].minX ? blocks[i].minX : positionX;
29257				}
29258
29259				// Check if a max limit is defined
29260				if (blocks[i].max !== null) {
29261					if (self.options.vertical && !self.options.horizontal) {
29262						positionY = positionY >= blocks[i].max ? blocks[i].max : positionY;
29263					}
29264					if (self.options.horizontal && !self.options.vertical) {
29265						positionX = positionX >= blocks[i].max ? blocks[i].max : positionX;
29266					}
29267				}
29268
29269				// Check if directional max limits are defined
29270				if (blocks[i].maxY != null) {
29271						positionY = positionY >= blocks[i].maxY ? blocks[i].maxY : positionY;
29272				}
29273				if (blocks[i].maxX != null) {
29274						positionX = positionX >= blocks[i].maxX ? blocks[i].maxX : positionX;
29275				}
29276
29277				var zindex = blocks[i].zindex;
29278
29279				// Move that element
29280				// (Set the new translation and append initial inline transforms.)
29281				var translate = 'translate3d(' + (self.options.horizontal ? positionX : '0') + 'px,' + (self.options.vertical ? positionY : '0') + 'px,' + zindex + 'px) ' + blocks[i].transform;
29282				self.elems[i].style[transformProp] = translate;
29283			}
29284			self.options.callback(positions);
29285		};
29286
29287		self.destroy = function() {
29288			for (var i = 0; i < self.elems.length; i++){
29289				self.elems[i].style.cssText = blocks[i].style;
29290			}
29291
29292			// Remove resize event listener if not pause, and pause
29293			if (!pause) {
29294				window.removeEventListener('resize', init);
29295				pause = true;
29296			}
29297
29298			// Clear the animation loop to prevent possible memory leak
29299			clearLoop(loopId);
29300			loopId = null;
29301		};
29302
29303		// Init
29304		init();
29305
29306		// Allow to recalculate the initial values whenever we want
29307		self.refresh = init;
29308
29309		return self;
29310	};
29311	return Rellax;
29312}));
29313
29314/*
29315 * OKVideo by OKFocus v2.3.2
29316 * http://okfoc.us
29317 *
29318 * Copyright 2014, OKFocus
29319 * Licensed under the MIT license.
29320 *
29321 */
29322var player, OKEvents, options, videoWidth, videoHeight, YTplayers, youtubePlayers = new Array();
29323// youtube player ready
29324function onYouTubeIframeAPIReady() {
29325	YTplayers = new Array();
29326	jQuery('.no-touch .uncode-video-container.video').each(function() {
29327		var playerY;
29328		if (jQuery(this).attr('data-provider') == 'youtube') {
29329			var id = jQuery(this).attr('data-id');
29330			options = jQuery(window).data('okoptions-' + id);
29331			options.time = jQuery(this).attr('data-t');
29332			playerY = new YT.Player('okplayer-' + id, {
29333				videoId: options.video ? options.video.id : null,
29334				playerVars: {
29335					'autohide': 1,
29336					'autoplay': 0, //options.autoplay,
29337					'disablekb': 1,
29338					'cc_load_policy': options.captions,
29339					'controls': 0,
29340					'enablejsapi': 1,
29341					'fs': 0,
29342					'modestbranding': 1,
29343					'origin': window.location.origin || (window.location.protocol + '//' + window.location.hostname),
29344					'iv_load_policy': options.annotations,
29345					'loop': options.loop,
29346					'showinfo': 0,
29347					'rel': 0,
29348					'wmode': 'opaque',
29349					'hd': options.hd,
29350					'mute': 1
29351				},
29352				events: {
29353					'onReady': OKEvents.yt.ready,
29354					'onStateChange': OKEvents.yt.onStateChange,
29355					'onError': OKEvents.yt.error
29356				}
29357			});
29358			YTplayers[id] = playerY;
29359			playerY.videoId = id;
29360		}
29361
29362	});
29363}
29364// vimeo player ready
29365function vimeoPlayerReady(id) {
29366	options = jQuery(window).data('okoptions-' + id);
29367	var jIframe = options.jobject,
29368		iframe = jIframe[0];
29369
29370	jIframe.attr('src', jIframe.data('src'));
29371	var playerV = $f(iframe); // `$f` is froogaloop, assumed is loaded
29372	// hide player until Vimeo hides controls...
29373	playerV.addEvent('ready', function(e) {
29374		OKEvents.v.onReady(iframe);
29375		var carouselContainer = jQuery(iframe).closest('.owl-carousel');
29376		if (carouselContainer.length) {
29377			UNCODE.owlPlayVideo(carouselContainer);
29378		}
29379		// "Do not try to add listeners or call functions before receiving this event."
29380		if (OKEvents.utils.isMobile()) {
29381			// mobile devices cannot listen for play event
29382			OKEvents.v.onPlay(playerV);
29383		} else {
29384			playerV.addEvent('play', OKEvents.v.onPlay(playerV));
29385			playerV.addEvent('pause', OKEvents.v.onPause);
29386			playerV.addEvent('finish', OKEvents.v.onFinish);
29387		}
29388		if (options.time != null) {
29389			var optsTimeStr = (options.time).replace('t=', ''),
29390				timeV = '';
29391
29392			if ( /[a-zA-Z]/g.test(optsTimeStr) ) {
29393				var timeArr = optsTimeStr.split(/([^\d.-])/);
29394				for ( var i = 0; i < timeArr.length; i++ ) {
29395					if ( timeArr[i] === 'h' ) {
29396						timeV += parseFloat(timeArr[i-1]) * 3600;
29397					} else if ( timeArr[i] === 'm' ) {
29398						timeV += parseFloat(timeArr[i-1]) * 60;
29399					} else if ( timeArr[i] === 's' ) {
29400						timeV += parseFloat(timeArr[i-1]);
29401					}
29402				}
29403			} else {
29404				timeV = optsTimeStr;
29405			}
29406
29407			playerV.api('seekTo', timeV);
29408		}
29409
29410		playerV.api('play');
29411		jQuery(iframe).css({
29412			visibility: 'visible',
29413			opacity: 1
29414		});
29415		jQuery(iframe).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
29416		jQuery(iframe).closest('#page-header').addClass('video-started');
29417		jQuery(iframe).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
29418
29419	});
29420}
29421OKEvents = {
29422	yt: {
29423		ready: function(event) {
29424			var id = event.target.videoId;
29425			youtubePlayers[id] = event.target;
29426			event.target.setVolume(options.volume);
29427			if (options.autoplay === 1) {
29428				if (options.playlist.list) {
29429					player.loadPlaylist(options.playlist.list, options.playlist.index, options.playlist.startSeconds, options.playlist.suggestedQuality);
29430				} else {
29431					var inCarousel = jQuery('#okplayer-' + id).closest('.owl-item');
29432					if (!inCarousel.length || (inCarousel.length && inCarousel.hasClass('active'))) {
29433						if (options.time != null) {
29434							event.target.seekTo(parseInt(options.time));
29435						}
29436						event.target.playVideo();
29437					} else {
29438						event.target.pauseVideo();
29439					}
29440				}
29441			}
29442			OKEvents.utils.isFunction(options.onReady) && options.onReady(event.target);
29443
29444			jQuery('#okplayer-' + id).closest('[data-provider]').on('uncode-resume', function(){
29445				if (options.time != null) {
29446					event.target.seekTo(parseInt(options.time)).playVideo();
29447				} else {
29448					event.target.seekTo(0).playVideo();
29449				}
29450			});
29451
29452			jQuery('#okplayer-' + id).closest('[data-provider]').on('uncode-pause', function(){
29453				if (options.time != null) {
29454					event.target.seekTo(parseInt(options.time)).pauseVideo();
29455				} else {
29456					event.target.seekTo(0).pauseVideo();
29457				}
29458			});
29459		},
29460		onStateChange: function(event) {
29461			var id = event.target.videoId;
29462			switch (event.data) {
29463				case -1:
29464					OKEvents.utils.isFunction(options.unstarted) && options.unstarted();
29465					break;
29466				case 0:
29467					OKEvents.utils.isFunction(options.onFinished) && options.onFinished();
29468					options.loop && event.target.playVideo();
29469					break;
29470				case 1:
29471					OKEvents.utils.isFunction(options.onPlay) && options.onPlay();
29472					setTimeout(function() {
29473						UNCODE.initVideoComponent(document.body, '.uncode-video-container.video:not(.drop-move), .uncode-video-container.self-video:not(.drop-move)');
29474						jQuery('#okplayer-' + id).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
29475						jQuery('#okplayer-' + id).closest('#page-header').addClass('video-started');
29476						jQuery('#okplayer-' + id).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
29477					}, 300);
29478					break;
29479				case 2:
29480					OKEvents.utils.isFunction(options.onPause) && options.onPause();
29481					break;
29482				case 3:
29483					OKEvents.utils.isFunction(options.buffering) && options.buffering();
29484					break;
29485				case 5:
29486					OKEvents.utils.isFunction(options.cued) && options.cued();
29487					break;
29488				default:
29489					throw "OKVideo: received invalid data from YT player.";
29490			}
29491		},
29492		error: function(event) {
29493			throw event;
29494		}
29495	},
29496	v: {
29497		onReady: function(target) {
29498			OKEvents.utils.isFunction(options.onReady) && options.onReady(target);
29499		},
29500		onPlay: function(player) {
29501			if (!OKEvents.utils.isMobile()) player.api('setVolume', options.volume);
29502			OKEvents.utils.isFunction(options.onPlay) && options.onPlay();
29503			jQuery(player.element).closest('.uncode-video-container:not(.t-entry-drop)').css('opacity', '1');
29504			jQuery(player.element).closest('#page-header').addClass('video-started');
29505			jQuery(player.element).closest('.background-wrapper').find('.block-bg-blend-mode.not-ie').css('opacity', '1');
29506		},
29507		onPause: function() {
29508			OKEvents.utils.isFunction(options.onPause) && options.onPause();
29509		},
29510		onFinish: function() {
29511			OKEvents.utils.isFunction(options.onFinish) && options.onFinish();
29512		}
29513	},
29514	utils: {
29515		isFunction: function(func) {
29516			if (typeof func === 'function') {
29517				return true;
29518			} else {
29519				return false;
29520			}
29521		},
29522		isMobile: function() {
29523			if (navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/)) {
29524				return true;
29525			} else {
29526				return false;
29527			}
29528		}
29529	}
29530};
29531
29532/**
29533 * vivus - JavaScript library to make drawing animation on SVG
29534 * @version v0.4.4
29535 * @link https://github.com/maxwellito/vivus
29536 * @license MIT
29537 */
29538
29539'use strict';
29540
29541(function () {
29542
29543  'use strict';
29544
29545/**
29546 * Pathformer
29547 * Beta version
29548 *
29549 * Take any SVG version 1.1 and transform
29550 * child elements to 'path' elements
29551 *
29552 * This code is purely forked from
29553 * https://github.com/Waest/SVGPathConverter
29554 */
29555
29556/**
29557 * Class constructor
29558 *
29559 * @param {DOM|String} element Dom element of the SVG or id of it
29560 */
29561function Pathformer(element) {
29562  // Test params
29563  if (typeof element === 'undefined') {
29564	throw new Error('Pathformer [constructor]: "element" parameter is required');
29565  }
29566
29567  // Set the element
29568  if (element.constructor === String) {
29569	element = document.getElementById(element);
29570	if (!element) {
29571	  throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID');
29572	}
29573  }
29574  if (element instanceof window.SVGElement ||
29575	  element instanceof window.SVGGElement ||
29576	  /^svg$/i.test(element.nodeName)) {
29577	this.el = element;
29578  } else {
29579	throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement');
29580  }
29581
29582  // Start
29583  this.scan(element);
29584}
29585
29586/**
29587 * List of tags which can be transformed
29588 * to path elements
29589 *
29590 * @type {Array}
29591 */
29592Pathformer.prototype.TYPES = ['line', 'ellipse', 'circle', 'polygon', 'polyline', 'rect'];
29593
29594/**
29595 * List of attribute names which contain
29596 * data. This array list them to check if
29597 * they contain bad values, like percentage.
29598 *
29599 * @type {Array}
29600 */
29601Pathformer.prototype.ATTR_WATCH = ['cx', 'cy', 'points', 'r', 'rx', 'ry', 'x', 'x1', 'x2', 'y', '
vendor: 24,640 bytes, lines 29601-30399
29601y1', 'y2'];
29602
29603/**
29604 * Finds the elements compatible for transform
29605 * and apply the liked method
29606 *
29607 * @param  {object} options Object from the constructor
29608 */
29609Pathformer.prototype.scan = function (svg) {
29610  var fn, element, pathData, pathDom,
29611	  elements = svg.querySelectorAll(this.TYPES.join(','));
29612
29613  for (var i = 0; i < elements.length; i++) {
29614	element = elements[i];
29615	fn = this[element.tagName.toLowerCase() + 'ToPath'];
29616	pathData = fn(this.parseAttr(element.attributes));
29617	pathDom = this.pathMaker(element, pathData);
29618	element.parentNode.replaceChild(pathDom, element);
29619  }
29620};
29621
29622
29623/**
29624 * Read `line` element to extract and transform
29625 * data, to make it ready for a `path` object.
29626 *
29627 * @param  {DOMelement} element Line element to transform
29628 * @return {object}			 Data for a `path` element
29629 */
29630Pathformer.prototype.lineToPath = function (element) {
29631  var newElement = {},
29632	  x1 = element.x1 || 0,
29633	  y1 = element.y1 || 0,
29634	  x2 = element.x2 || 0,
29635	  y2 = element.y2 || 0;
29636
29637  newElement.d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
29638  return newElement;
29639};
29640
29641/**
29642 * Read `rect` element to extract and transform
29643 * data, to make it ready for a `path` object.
29644 * The radius-border is not taken in charge yet.
29645 * (your help is more than welcomed)
29646 *
29647 * @param  {DOMelement} element Rect element to transform
29648 * @return {object}             Data for a `path` element
29649 */
29650Pathformer.prototype.rectToPath = function (element) {
29651  var newElement = {},
29652      x      = parseFloat(element.x)      || 0,
29653      y      = parseFloat(element.y)      || 0,
29654      width  = parseFloat(element.width)  || 0,
29655      height = parseFloat(element.height) || 0;
29656
29657  if (element.rx || element.ry) {
29658    var rx = parseInt(element.rx, 10) || -1,
29659        ry = parseInt(element.ry, 10) || -1;
29660    rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2);
29661    ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2);
29662
29663    newElement.d = 'M ' + (x + rx) + ',' + y + ' ' +
29664                   'L ' + (x + width - rx) + ',' + y + ' ' +
29665                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' +
29666                   'L ' + (x + width) + ',' + (y + height - ry) + ' ' +
29667                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' +
29668                   'L ' + (x + rx) + ',' + (y + height) + ' ' +
29669                   'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' +
29670                   'L ' + x + ',' + (y + ry) + ' ' +
29671                   'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y;
29672  }
29673  else {
29674    newElement.d = 'M' + x + ' ' + y + ' ' +
29675                   'L' + (x + width) + ' ' + y + ' ' +
29676                   'L' + (x + width) + ' ' + (y + height) + ' ' +
29677                   'L' + x + ' ' + (y + height) + ' Z';
29678  }
29679  return newElement;
29680};
29681
29682/**
29683 * Read `polyline` element to extract and transform
29684 * data, to make it ready for a `path` object.
29685 *
29686 * @param  {DOMelement} element Polyline element to transform
29687 * @return {object}             Data for a `path` element
29688 */
29689Pathformer.prototype.polylineToPath = function (element) {
29690  var newElement = {},
29691      points = element.points.trim().split(' '),
29692      i, path;
29693
29694  // Reformatting if points are defined without commas
29695  if (element.points.indexOf(',') === -1) {
29696    var formattedPoints = [];
29697    for (i = 0; i < points.length; i+=2) {
29698      formattedPoints.push(points[i] + ',' + points[i+1]);
29699    }
29700    points = formattedPoints;
29701  }
29702
29703  // Generate the path.d value
29704  path = 'M' + points[0];
29705  for(i = 1; i < points.length; i++) {
29706    if (points[i].indexOf(',') !== -1) {
29707      path += 'L' + points[i];
29708    }
29709  }
29710  newElement.d = path;
29711  return newElement;
29712};
29713
29714/**
29715 * Read `polygon` element to extract and transform
29716 * data, to make it ready for a `path` object.
29717 * This method rely on polylineToPath, because the
29718 * logic is similar. The path created is just closed,
29719 * so it needs an 'Z' at the end.
29720 *
29721 * @param  {DOMelement} element Polygon element to transform
29722 * @return {object}             Data for a `path` element
29723 */
29724Pathformer.prototype.polygonToPath = function (element) {
29725  var newElement = Pathformer.prototype.polylineToPath(element);
29726
29727  newElement.d += 'Z';
29728  return newElement;
29729};
29730
29731/**
29732 * Read `ellipse` element to extract and transform
29733 * data, to make it ready for a `path` object.
29734 *
29735 * @param  {DOMelement} element ellipse element to transform
29736 * @return {object}             Data for a `path` element
29737 */
29738Pathformer.prototype.ellipseToPath = function (element) {
29739  var newElement = {},
29740      rx = parseFloat(element.rx) || 0,
29741      ry = parseFloat(element.ry) || 0,
29742      cx = parseFloat(element.cx) || 0,
29743      cy = parseFloat(element.cy) || 0,
29744      startX = cx - rx,
29745      startY = cy,
29746      endX = parseFloat(cx) + parseFloat(rx),
29747      endY = cy;
29748
29749  newElement.d = 'M' + startX + ',' + startY +
29750                 'A' + rx + ',' + ry + ' 0,1,1 ' + endX + ',' + endY +
29751                 'A' + rx + ',' + ry + ' 0,1,1 ' + startX + ',' + endY;
29752  return newElement;
29753};
29754
29755/**
29756 * Read `circle` element to extract and transform
29757 * data, to make it ready for a `path` object.
29758 *
29759 * @param  {DOMelement} element Circle element to transform
29760 * @return {object}             Data for a `path` element
29761 */
29762Pathformer.prototype.circleToPath = function (element) {
29763  var newElement = {},
29764      r  = parseFloat(element.r)  || 0,
29765      cx = parseFloat(element.cx) || 0,
29766      cy = parseFloat(element.cy) || 0,
29767      startX = cx - r,
29768      startY = cy,
29769      endX = parseFloat(cx) + parseFloat(r),
29770      endY = cy;
29771
29772  newElement.d =  'M' + startX + ',' + startY +
29773                  'A' + r + ',' + r + ' 0,1,1 ' + endX + ',' + endY +
29774                  'A' + r + ',' + r + ' 0,1,1 ' + startX + ',' + endY;
29775  return newElement;
29776};
29777
29778/**
29779 * Create `path` elements form original element
29780 * and prepared objects
29781 *
29782 * @param  {DOMelement} element  Original element to transform
29783 * @param  {object} pathData     Path data (from `toPath` methods)
29784 * @return {DOMelement}          Path element
29785 */
29786Pathformer.prototype.pathMaker = function (element, pathData) {
29787  var i, attr, pathTag = document.createElementNS('http://www.w3.org/2000/svg','path');
29788  for(i = 0; i < element.attributes.length; i++) {
29789    attr = element.attributes[i];
29790    if (this.ATTR_WATCH.indexOf(attr.name) === -1) {
29791      pathTag.setAttribute(attr.name, attr.value);
29792    }
29793  }
29794  for(i in pathData) {
29795    pathTag.setAttribute(i, pathData[i]);
29796  }
29797  return pathTag;
29798};
29799
29800/**
29801 * Parse attributes of a DOM element to
29802 * get an object of attribute => value
29803 *
29804 * @param  {NamedNodeMap} attributes Attributes object from DOM element to parse
29805 * @return {object}                  Object of attributes
29806 */
29807Pathformer.prototype.parseAttr = function (element) {
29808  var attr, output = {};
29809  for (var i = 0; i < element.length; i++) {
29810    attr = element[i];
29811    // Check if no data attribute contains '%', or the transformation is impossible
29812    if (this.ATTR_WATCH.indexOf(attr.name) !== -1 && attr.value.indexOf('%') !== -1) {
29813      throw new Error('Pathformer [parseAttr]: a SVG shape got values in percentage. This cannot be transformed into \'path\' tags. Please use \'viewBox\'.');
29814    }
29815    output[attr.name] = attr.value;
29816  }
29817  return output;
29818};
29819
29820  'use strict';
29821
29822var setupEnv, requestAnimFrame, cancelAnimFrame, parsePositiveInt;
29823
29824/**
29825 * Vivus
29826 * Beta version
29827 *
29828 * Take any SVG and make the animation
29829 * to give give the impression of live drawing
29830 *
29831 * This in more than just inspired from codrops
29832 * At that point, it's a pure fork.
29833 */
29834
29835/**
29836 * Class constructor
29837 * option structure
29838 *   type: 'delayed'|'sync'|'oneByOne'|'script' (to know if the items must be drawn synchronously or not, default: delayed)
29839 *   duration: <int> (in frames)
29840 *   start: 'inViewport'|'manual'|'autostart' (start automatically the animation, default: inViewport)
29841 *   delay: <int> (delay between the drawing of first and last path)
29842 *   dashGap <integer> whitespace extra margin between dashes
29843 *   pathTimingFunction <function> timing animation function for each path element of the SVG
29844 *   animTimingFunction <function> timing animation function for the complete SVG
29845 *   forceRender <boolean> force the browser to re-render all updated path items
29846 *   selfDestroy <boolean> removes all extra styling on the SVG, and leaves it as original
29847 *
29848 * The attribute 'type' is by default on 'delayed'.
29849 *  - 'delayed'
29850 *    all paths are draw at the same time but with a
29851 *    little delay between them before start
29852 *  - 'sync'
29853 *    all path are start and finish at the same time
29854 *  - 'oneByOne'
29855 *    only one path is draw at the time
29856 *    the end of the first one will trigger the draw
29857 *    of the next one
29858 *
29859 * All these values can be overwritten individually
29860 * for each path item in the SVG
29861 * The value of frames will always take the advantage of
29862 * the duration value.
29863 * If you fail somewhere, an error will be thrown.
29864 * Good luck.
29865 *
29866 * @constructor
29867 * @this {Vivus}
29868 * @param {DOM|String}   element  Dom element of the SVG or id of it
29869 * @param {Object}       options  Options about the animation
29870 * @param {Function}     callback Callback for the end of the animation
29871 */
29872function Vivus (element, options, callback) {
29873
29874  setupEnv();
29875
29876  // Setup
29877  this.isReady = false;
29878  this.setElement(element, options);
29879  this.setOptions(options);
29880  this.setCallback(callback);
29881
29882  if (this.isReady) {
29883    this.init();
29884  }
29885}
29886
29887/**
29888 * Timing functions
29889 **************************************
29890 *
29891 * Default functions to help developers.
29892 * It always take a number as parameter (between 0 to 1) then
29893 * return a number (between 0 and 1)
29894 */
29895Vivus.LINEAR          = function (x) {return x;};
29896Vivus.EASE            = function (x) {return -Math.cos(x * Math.PI) / 2 + 0.5;};
29897Vivus.EASE_OUT        = function (x) {return 1 - Math.pow(1-x, 3);};
29898Vivus.EASE_IN         = function (x) {return Math.pow(x, 3);};
29899Vivus.EASE_OUT_BOUNCE = function (x) {
29900  var base = -Math.cos(x * (0.5 * Math.PI)) + 1,
29901    rate = Math.pow(base,1.5),
29902    rateR = Math.pow(1 - x, 2),
29903    progress = -Math.abs(Math.cos(rate * (2.5 * Math.PI) )) + 1;
29904  return (1- rateR) + (progress * rateR);
29905};
29906
29907
29908/**
29909 * Setters
29910 **************************************
29911 */
29912
29913/**
29914 * Check and set the element in the instance
29915 * The method will not return anything, but will throw an
29916 * error if the parameter is invalid
29917 *
29918 * @param {DOM|String}   element  SVG Dom element or id of it
29919 */
29920Vivus.prototype.setElement = function (element, options) {
29921  var onLoad, self;
29922
29923  // Basic check
29924  if (typeof element === 'undefined') {
29925    throw new Error('Vivus [constructor]: "element" parameter is required');
29926  }
29927
29928  // Set the element
29929  if (element.constructor === String) {
29930    element = document.getElementById(element);
29931    if (!element) {
29932      throw new Error('Vivus [constructor]: "element" parameter is not related to an existing ID');
29933    }
29934  }
29935  this.parentEl = element;
29936
29937  // Load the SVG with XMLHttpRequest and extract the SVG
29938  if (options && options.file) {
29939    var self = this;
29940    onLoad = function (e) {
29941      var domSandbox = document.createElement('div');
29942      domSandbox.innerHTML = this.responseText;
29943
29944      var svgTag = domSandbox.querySelector('svg');
29945      if (!svgTag) {
29946        throw new Error('Vivus [load]: Cannot find the SVG in the loaded file : ' + options.file);
29947      }
29948
29949      self.el = svgTag
29950      self.el.setAttribute('width', '100%');
29951      self.el.setAttribute('height', '100%');
29952      self.parentEl.appendChild(self.el)
29953      self.isReady = true;
29954      self.init();
29955      self = null;
29956    }
29957
29958    var oReq = new window.XMLHttpRequest();
29959    oReq.addEventListener('load', onLoad);
29960    oReq.open('GET', options.file);
29961    oReq.send();
29962    return;
29963  }
29964
29965  switch (element.constructor) {
29966  case window.SVGSVGElement:
29967  case window.SVGElement:
29968  case window.SVGGElement:
29969    this.el = element;
29970    this.isReady = true;
29971    break;
29972
29973  case window.HTMLObjectElement:
29974    self = this;
29975    onLoad = function (e) {
29976      if (self.isReady) {
29977        return;
29978      }
29979      self.el = element.contentDocument && element.contentDocument.querySelector('svg');
29980      if (!self.el && e) {
29981        throw new Error('Vivus [constructor]: object loaded does not contain any SVG');
29982      }
29983      else if (self.el) {
29984        if (element.getAttribute('built-by-vivus')) {
29985          self.parentEl.insertBefore(self.el, element);
29986          self.parentEl.removeChild(element);
29987          self.el.setAttribute('width', '100%');
29988          self.el.setAttribute('height', '100%');
29989        }
29990        self.isReady = true;
29991        self.init();
29992        self = null;
29993      }
29994    };
29995
29996    if (!onLoad()) {
29997      element.addEventListener('load', onLoad);
29998    }
29999    break;
30000
30001  default:
30002    throw new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)');
30003  }
30004};
30005
30006/**
30007 * Set up user option to the instance
30008 * The method will not return anything, but will throw an
30009 * error if the parameter is invalid
30010 *
30011 * @param  {object} options Object from the constructor
30012 */
30013Vivus.prototype.setOptions = function (options) {
30014  var allowedTypes = ['delayed', 'sync', 'async', 'nsync', 'oneByOne', 'scenario', 'scenario-sync'];
30015  var allowedStarts =  ['inViewport', 'manual', 'autostart'];
30016
30017  // Basic check
30018  if (options !== undefined && options.constructor !== Object) {
30019    throw new Error('Vivus [constructor]: "options" parameter must be an object');
30020  }
30021  else {
30022    options = options || {};
30023  }
30024
30025  // Set the animation type
30026  if (options.type && allowedTypes.indexOf(options.type) === -1) {
30027    throw new Error('Vivus [constructor]: ' + options.type + ' is not an existing animation `type`');
30028  }
30029  else {
30030    this.type = options.type || allowedTypes[0];
30031  }
30032
30033  // Set the start type
30034  if (options.start && allowedStarts.indexOf(options.start) === -1) {
30035    throw new Error('Vivus [constructor]: ' + options.start + ' is not an existing `start` option');
30036  }
30037  else {
30038    this.start = options.start || allowedStarts[0];
30039  }
30040
30041  this.isIE         = (window.navigator.userAgent.indexOf('MSIE') !== -1 || window.navigator.userAgent.indexOf('Trident/') !== -1 || window.navigator.userAgent.indexOf('Edge/') !== -1 );
30042  this.duration     = parsePositiveInt(options.duration, 120);
30043  this.delay        = parsePositiveInt(options.delay, null);
30044  //Uncode addition
30045  this.delayStart   = parsePositiveInt(options.delayStart, null);
30046  //#END
30047  this.dashGap      = parsePositiveInt(options.dashGap, 1);
30048  this.forceRender  = options.hasOwnProperty('forceRender') ? !!options.forceRender : this.isIE;
30049  this.reverseStack = !!options.reverseStack;
30050  this.selfDestroy  = !!options.selfDestroy;
30051  this.onReady      = options.onReady;
30052  this.map          = [];
30053  this.frameLength  = this.currentFrame = this.delayUnit = this.speed = this.handle = null;
30054
30055  this.ignoreInvisible = options.hasOwnProperty('ignoreInvisible') ? !!options.ignoreInvisible : false;
30056
30057  this.animTimingFunction = options.animTimingFunction || Vivus.LINEAR;
30058  this.pathTimingFunction = options.pathTimingFunction || Vivus.LINEAR;
30059
30060  if (this.delay >= this.duration) {
30061    throw new Error('Vivus [constructor]: delay must be shorter than duration');
30062  }
30063};
30064
30065/**
30066 * Set up callback to the instance
30067 * The method will not return enything, but will throw an
30068 * error if the parameter is invalid
30069 *
30070 * @param  {Function} callback Callback for the animation end
30071 */
30072Vivus.prototype.setCallback = function (callback) {
30073  // Basic check
30074  if (!!callback && callback.constructor !== Function) {
30075    throw new Error('Vivus [constructor]: "callback" parameter must be a function');
30076  }
30077  this.callback = callback || function () {};
30078};
30079
30080
30081/**
30082 * Core
30083 **************************************
30084 */
30085
30086/**
30087 * Map the svg, path by path.
30088 * The method return nothing, it just fill the
30089 * `map` array. Each item in this array represent
30090 * a path element from the SVG, with informations for
30091 * the animation.
30092 *
30093 * ```
30094 * [
30095 *   {
30096 *     el: <DOMobj> the path element
30097 *     length: <number> length of the path line
30098 *     startAt: <number> time start of the path animation (in frames)
30099 *     duration: <number> path animation duration (in frames)
30100 *   },
30101 *   ...
30102 * ]
30103 * ```
30104 *
30105 */
30106Vivus.prototype.mapping = function () {
30107  var i, paths, path, pAttrs, pathObj, totalLength, lengthMeter, timePoint;
30108  timePoint = totalLength = lengthMeter = 0;
30109  paths = this.el.querySelectorAll('path');
30110
30111  for (i = 0; i < paths.length; i++) {
30112    path = paths[i];
30113    if (this.isInvisible(path)) {
30114      continue;
30115    }
30116    pathObj = {
30117      el: path,
30118      length: Math.ceil(path.getTotalLength())
30119    };
30120    // Test if the path length is correct
30121    if (isNaN(pathObj.length)) {
30122      if (window.console && console.warn) {
30123        console.warn('Vivus [mapping]: cannot retrieve a path element length', path);
30124      }
30125      continue;
30126    }
30127    this.map.push(pathObj);
30128    path.style.strokeDasharray  = pathObj.length + ' ' + (pathObj.length + this.dashGap * 2);
30129    path.style.strokeDashoffset = pathObj.length + this.dashGap;
30130    pathObj.length += this.dashGap;
30131    totalLength += pathObj.length;
30132
30133    this.renderPath(i);
30134  }
30135
30136  totalLength = totalLength === 0 ? 1 : totalLength;
30137  this.delay = this.delay === null ? this.duration / 3 : this.delay;
30138  this.delayUnit = this.delay / (paths.length > 1 ? paths.length - 1 : 1);
30139
30140  // Reverse stack if asked
30141  if (this.reverseStack) {
30142    this.map.reverse();
30143  }
30144
30145  for (i = 0; i < this.map.length; i++) {
30146    pathObj = this.map[i];
30147
30148    switch (this.type) {
30149    case 'delayed':
30150      pathObj.startAt = this.delayUnit * i;
30151      pathObj.duration = this.duration - this.delay;
30152      break;
30153
30154    case 'oneByOne':
30155      pathObj.startAt = lengthMeter / totalLength * this.duration;
30156      pathObj.duration = pathObj.length / totalLength * this.duration;
30157      break;
30158
30159    case 'sync':
30160    case 'async':
30161    case 'nsync':
30162      pathObj.startAt = 0;
30163      pathObj.duration = this.duration;
30164      break;
30165
30166    case 'scenario-sync':
30167      path = pathObj.el;
30168      pAttrs = this.parseAttr(path);
30169      pathObj.startAt = timePoint + (parsePositiveInt(pAttrs['data-delay'], this.delayUnit) || 0);
30170      pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
30171      timePoint = pAttrs['data-async'] !== undefined ? pathObj.startAt : pathObj.startAt + pathObj.duration;
30172      this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
30173      break;
30174
30175    case 'scenario':
30176      path = pathObj.el;
30177      pAttrs = this.parseAttr(path);
30178      pathObj.startAt = parsePositiveInt(pAttrs['data-start'], this.delayUnit) || 0;
30179      pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
30180      this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
30181      break;
30182    }
30183    lengthMeter += pathObj.length;
30184    this.frameLength = this.frameLength || this.duration;
30185  }
30186};
30187
30188/**
30189 * Interval method to draw the SVG from current
30190 * position of the animation. It update the value of
30191 * `currentFrame` and re-trace the SVG.
30192 *
30193 * It use this.handle to store the requestAnimationFrame
30194 * and clear it one the animation is stopped. So this
30195 * attribute can be used to know if the animation is
30196 * playing.
30197 *
30198 * Once the animation at the end, this method will
30199 * trigger the Vivus callback.
30200 *
30201 */
30202Vivus.prototype.drawer = function () {
30203  var self = this;
30204  this.currentFrame += this.speed;
30205
30206  if (this.currentFrame <= 0) {
30207    this.stop();
30208    this.reset();
30209  } else if (this.currentFrame >= this.frameLength) {
30210    this.stop();
30211    this.currentFrame = this.frameLength;
30212    this.trace();
30213    if (this.selfDestroy) {
30214      this.destroy();
30215    }
30216  } else {
30217    this.trace();
30218    this.handle = requestAnimFrame(function () {
30219      self.drawer();
30220    });
30221    return;
30222  }
30223
30224  this.callback(this);
30225  if (this.instanceCallback) {
30226    this.instanceCallback(this);
30227    this.instanceCallback = null;
30228  }
30229};
30230
30231/**
30232 * Draw the SVG at the current instant from the
30233 * `currentFrame` value. Here is where most of the magic is.
30234 * The trick is to use the `strokeDashoffset` style property.
30235 *
30236 * For optimisation reasons, a new property called `progress`
30237 * is added in each item of `map`. This one contain the current
30238 * progress of the path element. Only if the new value is different
30239 * the new value will be applied to the DOM element. This
30240 * method save a lot of resources to re-render the SVG. And could
30241 * be improved if the animation couldn't be played forward.
30242 *
30243 */
30244Vivus.prototype.trace = function () {
30245  var i, progress, path, currentFrame;
30246  currentFrame = this.animTimingFunction(this.currentFrame / this.frameLength) * this.frameLength;
30247  for (i = 0; i < this.map.length; i++) {
30248    path = this.map[i];
30249    progress = (currentFrame - path.startAt) / path.duration;
30250    progress = this.pathTimingFunction(Math.max(0, Math.min(1, progress)));
30251    if (path.progress !== progress) {
30252      path.progress = progress;
30253      path.el.style.strokeDashoffset = Math.floor(path.length * (1 - progress));
30254      this.renderPath(i);
30255    }
30256  }
30257};
30258
30259/**
30260 * Method forcing the browser to re-render a path element
30261 * from it's index in the map. Depending on the `forceRender`
30262 * value.
30263 * The trick is to replace the path element by it's clone.
30264 * This practice is not recommended because it's asking more
30265 * ressources, too much DOM manupulation..
30266 * but it's the only way to let the magic happen on IE.
30267 * By default, this fallback is only applied on IE.
30268 *
30269 * @param  {Number} index Path index
30270 */
30271Vivus.prototype.renderPath = function (index) {
30272  if (this.forceRender && this.map && this.map[index]) {
30273    var pathObj = this.map[index],
30274        newPath = pathObj.el.cloneNode(true);
30275    pathObj.el.parentNode.replaceChild(newPath, pathObj.el);
30276    pathObj.el = newPath;
30277  }
30278};
30279
30280/**
30281 * When the SVG object is loaded and ready,
30282 * this method will continue the initialisation.
30283 *
30284 * This this mainly due to the case of passing an
30285 * object tag in the constructor. It will wait
30286 * the end of the loading to initialise.
30287 *
30288 */
30289Vivus.prototype.init = function () {
30290  // Set object variables
30291  this.frameLength = 0;
30292  this.currentFrame = 0;
30293  this.map = [];
30294
30295  // Start
30296  new Pathformer(this.el);
30297  this.mapping();
30298  this.starter();
30299
30300  if (this.onReady) {
30301    this.onReady(this);
30302  }
30303};
30304
30305/**
30306 * Trigger to start of the animation.
30307 * Depending on the `start` value, a different script
30308 * will be applied.
30309 *
30310 * If the `start` value is not valid, an error will be thrown.
30311 * Even if technically, this is impossible.
30312 *
30313 */
30314Vivus.prototype.starter = function () {
30315  switch (this.start) {
30316  case 'manual':
30317    return;
30318
30319  case 'autostart':
30320    this.play();
30321    break;
30322
30323  case 'inViewport':
30324    var self = this,
30325    listener = function () {
30326      if (self.isInViewport(self.parentEl, 1)) {
30327        self.play();
30328        window.removeEventListener('scroll', listener);
30329        //Uncode addition
30330        window.removeEventListener('fp-slide-changed', listener);
30331        window.removeEventListener('fp-slide-scroll', listener);
30332        //#END
30333      }
30334    };
30335    window.addEventListener('scroll', listener);
30336    //Uncode addition
30337    window.addEventListener('fp-slide-changed', listener);
30338    window.addEventListener('fp-slide-scroll', listener);
30339    //#END
30340    listener();
30341    break;
30342  }
30343};
30344
30345
30346/**
30347 * Controls
30348 **************************************
30349 */
30350
30351/**
30352 * Get the current status of the animation between
30353 * three different states: 'start', 'progress', 'end'.
30354 * @return {string} Instance status
30355 */
30356Vivus.prototype.getStatus = function () {
30357  return this.currentFrame === 0 ? 'start' : this.currentFrame === this.frameLength ? 'end' : 'progress';
30358};
30359
30360/**
30361 * Reset the instance to the initial state : undraw
30362 * Be careful, it just reset the animation, if you're
30363 * playing the animation, this won't stop it. But just
30364 * make it start from start.
30365 *
30366 */
30367Vivus.prototype.reset = function () {
30368  return this.setFrameProgress(0);
30369};
30370
30371/**
30372 * Set the instance to the final state : drawn
30373 * Be careful, it just set the animation, if you're
30374 * playing the animation on rewind, this won't stop it.
30375 * But just make it start from the end.
30376 *
30377 */
30378Vivus.prototype.finish = function () {
30379  return this.setFrameProgress(1);
30380};
30381
30382/**
30383 * Set the level of progress of the drawing.
30384 *
30385 * @param {number} progress Level of progress to set
30386 */
30387Vivus.prototype.setFrameProgress = function (progress) {
30388  progress = Math.min(1, Math.max(0, progress));
30389  this.currentFrame = Math.round(this.frameLength * progress);
30390  this.trace();
30391  return this;
30392};
30393
30394/**
30395 * Play the animation at the desired speed.
30396 * Speed must be a valid number (no zero).
30397 * By default, the speed value is 1.
30398 * But a negative value is accepted to go forward.
30399 *
30400 * And works with float too.
30401 * But don't forget we are in JavaScript, se be nice
30402 * with him and give him a 1/2^x value.
30403 *
30404 * @param  {number} speed Animation speed [optional]
30405 */
30406Vivus.prototype.play = function (speed, callback) {
30407  this.instanceCallback = null;
30408
30409  if (speed && typeof speed === 'function') {
30410    this.instanceCallback = speed; // first parameter is actually the callback function
30411    speed = null;
30412  }
30413  else if (speed && typeof speed !== 'number') {
30414    throw new Error('Vivus [play]: invalid speed');
30415  }
30416  // if the first parameter wasn't the callback, check if the seconds was
30417  if (callback && typeof(callback) === 'function' && !this.instanceCallback) {
30418    this.instanceCallback = callback;
30419  }
30420
30421
30422  this.speed = speed || 1;
30423  //Uncode addition
30424  if (!this.handle) {
30425    var $this = this,
30426    delay = (this.delayStart != null) ? this.delayStart : 0;
30427    setTimeout(function() {
30428      $this.drawer();
30429    }, delay);
30430  }
30431  //#END
30432  return this;
30433};
30434
30435/**
30436 * Stop the current animation, if on progress.
30437 * Should not trigger any error.
30438 *
30439 */
30440Vivus.prototype.stop = function () {
30441  if (this.handle) {
30442    cancelAnimFrame(this.handle);
30443    this.handle = null;
30444  }
30445  return this;
30446};
30447
30448/**
30449 * Destroy the instance.
30450 * Remove all bad styling attributes on all
30451 * path tags
30452 *
30453 */
30454Vivus.prototype.destroy = function () {
30455  this.stop();
30456  var i, path;
30457  for (i = 0; i < this.map.length; i++) {
30458    path = this.map[i];
30459    path.el.style.strokeDashoffset = null;
30460    path.el.style.strokeDasharray = null;
30461    this.renderPath(i);
30462  }
30463};
30464
30465
30466/**
30467 * Utils methods
30468 * include methods from Codrops
30469 **************************************
30470 */
30471
30472/**
30473 * Method to best guess if a path should added into
30474 * the animation or not.
30475 *
30476 * 1. Use the `data-vivus-ignore` attribute if set
30477 * 2. Check if the instance must ignore invisible paths
30478 * 3. Check if the path is visible
30479 *
30480 * For now the visibility checking is unstable.
30481 * It will be used for a beta phase.
30482 *
30483 * Other improvments are planned. Like detecting
30484 * is the path got a stroke or a valid opacity.
30485 */
30486Vivus.prototype.isInvisible = function (el) {
30487  var rect,
30488    ignoreAttr = el.getAttribute('data-ignore');
30489
30490  if (ignoreAttr !== null) {
30491    return ignoreAttr !== 'false';
30492  }
30493
30494  if (this.ignoreInvisible) {
30495    rect = el.getBoundingClientRect();
30496    return !rect.width && !rect.height;
30497  }
30498  else {
30499    return false;
30500  }
30501};
30502
30503/**
30504 * Parse attributes of a DOM element to
30505 * get an object of {attributeName => attributeValue}
30506 *
30507 * @param  {object} element DOM element to parse
30508 * @return {object}         Object of attributes
30509 */
30510Vivus.prototype.parseAttr = function (element) {
30511  var attr, output = {};
30512  if (element && element.attributes) {
30513    for (var i = 0; i < element.attributes.length; i++) {
30514      attr = element.attributes[i];
30515      output[attr.name] = attr.value;
30516    }
30517  }
30518  return output;
30519};
30520
30521/**
30522 * Reply if an element is in the page viewport
30523 *
30524 * @param  {object} el Element to observe
30525 * @param  {number} h  Percentage of height
30526 * @return {boolean}
30527 */
30528Vivus.prototype.isInViewport = function (el, h) {
30529  var scrolled   = this.scrollY(),
30530    viewed       = scrolled + this.getViewportH(),
30531    elBCR        = el.getBoundingClientRect(),
30532    elHeight     = elBCR.height,
30533    elTop        = scrolled + elBCR.top,
30534    elBottom     = elTop + elHeight;
30535
30536  // if 0, the element is considered in the viewport as soon as it enters.
30537  // if 1, the element is considered in the viewport only when it's fully inside
30538  // value in percentage (1 >= h >= 0)
30539  h = h || 0;
30540
30541  return (elTop + elHeight * h) <= viewed && (elBottom) >= scrolled;
30542};
30543
30544
30545/**
30546 * Get the viewport height in pixels
30547 *
30548 * @return {integer} Viewport height
30549 */
30550Vivus.prototype.getViewportH = function () {
30551  var client = this.docElem.clientHeight,
30552    inner = window.innerHeight;
30553
30554  if (client < inner) {
30555    return inner;
30556  }
30557  else {
30558    return client;
30559  }
30560};
30561
30562/**
30563 * Get the page Y offset
30564 *
30565 * @return {integer} Page Y offset
30566 */
30567Vivus.prototype.scrollY = function () {
30568  return window.pageYOffset || this.docElem.scrollTop;
30569};
30570
30571setupEnv = function () {
30572
30573  if (Vivus.prototype.docElem) {
30574    return;
30575  }
30576
30577  /**
30578   * Alias for document element
30579   *
30580   * @type {DOMelement}
30581   */
30582  Vivus.prototype.docElem = window.document.documentElement;
30583
30584  /**
30585   * Alias for `requestAnimationFrame` or
30586   * `setTimeout` function for deprecated browsers.
30587   *
30588   */
30589  requestAnimFrame = (function () {
30590    return (
30591      window.requestAnimationFrame       ||
30592      window.webkitRequestAnimationFrame ||
30593      window.mozRequestAnimationFrame    ||
30594      window.oRequestAnimationFrame      ||
30595      window.msRequestAnimationFrame     ||
30596      function(/* function */ callback){
30597        return window.setTimeout(callback, 1000 / 60);
30598      }
30599    );
30600  })();
30601
30602  /**
30603   * Alias for `cancelAnimationFrame` or
30604   * `cancelTimeout` function for deprecated browsers.
30605   *
30606   */
30607  cancelAnimFrame = (function () {
30608    return (
30609      window.cancelAnimationFrame       ||
30610      window.webkitCancelAnimationFrame ||
30611      window.mozCancelAnimationFrame    ||
30612      window.oCancelAnimationFrame      ||
30613      window.msCancelAnimationFrame     ||
30614      function(id){
30615        return window.clearTimeout(id);
30616      }
30617    );
30618  })();
30619};
30620
30621/**
30622 * Parse string to integer.
30623 * If the number is not positive or null
30624 * the method will return the default value
30625 * or 0 if undefined
30626 *
30627 * @param {string} value String to parse
30628 * @param {*}
30628 defaultValue Value to return if the result parsed is invalid
30629 * @return {number}
30630 *
30631 */
30632parsePositiveInt = function (value, defaultValue) {
30633  var output = parseInt(value, 10);
30634  return (output >= 0) ? output : defaultValue;
30635};
30636
30637
30638  if (typeof define === 'function' && define.amd) {
30639    // AMD. Register as an anonymous module.
30640    define([], function() {
30641      return Vivus;
30642    });
30643  } else if (typeof exports === 'object') {
30644    // Node. Does not work with strict CommonJS, but
30645    // only CommonJS-like environments that support module.exports,
30646    // like Node.
30647    module.exports = Vivus;
30648  } else {
30649    // Browser globals
30650    window.Vivus = Vivus;
30651  }
30652
30653}());

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.